Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp
Render():
// Draw translucency.
TArray<FScreenPassTexture> TSRMoireInputTextures;
if (!bHasRayTracedOverlay && TranslucencyViewsToRender != ETranslucencyView::None)
{
RDG_CSV_STAT_EXCLUSIVE_SCOPE(GraphBuilder, RenderTranslucency);
SCOPE_CYCLE_COUNTER(STAT_TranslucencyDrawTime);
RDG_EVENT_SCOPE(GraphBuilder, "Translucency");
// Raytracing doesn't need the distortion effect.
const bool bShouldRenderDistortion = TranslucencyViewsToRender != ETranslucencyView::RayTracing;
#if RHI_RAYTRACING
if (EnumHasAnyFlags(TranslucencyViewsToRender, ETranslucencyView::RayTracing))
{
RenderRayTracingTranslucency(GraphBuilder, SceneTextures.Color);
EnumRemoveFlags(TranslucencyViewsToRender, ETranslucencyView::RayTracing);
}
#endif
for (FViewInfo& View : Views)
{
if (GetViewPipelineState(View).ReflectionsMethod == EReflectionsMethod::Lumen)
{
RenderLumenFrontLayerTranslucencyReflections(GraphBuilder, View, SceneTextures, LumenFrameTemporaries);
}
}
// Extract TSR's moire heuristic luminance before renderering translucency into the scene color.
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
if (ITemporalUpscaler::GetMainTAAPassConfig(View) == EMainTAAPassConfig::TSR)
{
if (TSRMoireInputTextures.Num() == 0)
{
TSRMoireInputTextures.SetNum(Views.Num());
}
TSRMoireInputTextures[ViewIndex] = AddTSRComputeMoireLuma(GraphBuilder, View.ShaderMap, FScreenPassTexture(SceneTextures.Color.Target, View.ViewRect));
}
}
// Sort objects' triangles
for (FViewInfo& View : Views)
{
if (OIT::IsEnabled(EOITSortingType::SortedTriangles, View))
{
OIT::AddSortTrianglesPass(GraphBuilder, View, Scene->OITSceneData, FTriangleSortingOrder::BackToFront);
}
}
// Render all remaining translucency views.
GraphBuilder.SetCommandListStat(GET_STATID(STAT_CLM_Translucency));
RenderTranslucency(GraphBuilder, SceneTextures, TranslucencyLightingVolumeTextures, &TranslucencyResourceMap, TranslucencyViewsToRender, InstanceCullingManager);
TranslucencyViewsToRender = ETranslucencyView::None;
// Compose hair before velocity/distortion pass since these pass write depth value,
// and this would make the hair composition fails in this cases.
if (GetHairStrandsComposition() == EHairStrandsCompositionType::AfterTranslucent)
{
RDG_GPU_STAT_SCOPE(GraphBuilder, HairRendering);
RenderHairComposition(GraphBuilder, Views, SceneTextures.Color.Target, SceneTextures.Depth.Target, SceneTextures.Velocity);
}
if (bShouldRenderDistortion)
{
GraphBuilder.SetCommandListStat(GET_STATID(STAT_CLM_Distortion));
RenderDistortion(GraphBuilder, SceneTextures.Color.Target, SceneTextures.Depth.Target);
}
if (bShouldRenderVelocities)
{
const bool bRecreateSceneTextures = !HasBeenProduced(SceneTextures.Velocity);
GraphBuilder.SetCommandListStat(GET_STATID(STAT_CLM_TranslucentVelocity));
RenderVelocities(GraphBuilder, SceneTextures, EVelocityPass::Translucent, false);
if (bRecreateSceneTextures)
{
// Rebuild scene textures to include newly allocated velocity.
SceneTextures.UniformBuffer = CreateSceneTextureUniformBuffer(GraphBuilder, &SceneTextures, FeatureLevel, SceneTextures.SetupMode);
}
}
GraphBuilder.SetCommandListStat(GET_STATID(STAT_CLM_AfterTranslucency));
}
else if (GetHairStrandsComposition() == EHairStrandsCompositionType::AfterTranslucent)
{
RDG_GPU_STAT_SCOPE(GraphBuilder, HairRendering);
RenderHairComposition(GraphBuilder, Views, SceneTextures.Color.Target, SceneTextures.Depth.Target, SceneTextures.Velocity);
}
Translucency(AfterDOF)
void FDeferredShadingSceneRenderer::RenderTranslucency(
FRDGBuilder& GraphBuilder,
const FSceneTextures& SceneTextures,
const FTranslucencyLightingVolumeTextures& TranslucentLightingVolumeTextures,
FTranslucencyPassResourcesMap* OutTranslucencyResourceMap,
ETranslucencyView ViewsToRender,
FInstanceCullingManager& InstanceCullingManager)
{
if (!EnumHasAnyFlags(ViewsToRender, ETranslucencyView::UnderWater | ETranslucencyView::AboveWater))
{
return;
}
RDG_GPU_STAT_SCOPE(GraphBuilder, Translucency);
DynamicRenderScaling::FRDGScope DynamicTranslucencyResolutionScope(GraphBuilder, GDynamicTranslucencyResolution);
FRDGTextureRef SceneColorCopyTexture = nullptr;
if (EnumHasAnyFlags(ViewsToRender, ETranslucencyView::AboveWater))
{
SceneColorCopyTexture = AddCopySceneColorPass(GraphBuilder, Views, SceneTextures.Color);
}
const auto ShouldRenderView = [&](const FViewInfo& View, ETranslucencyView TranslucencyView)
{
return View.ShouldRenderView() && EnumHasAnyFlags(TranslucencyView, ViewsToRender);
};
// Create a shared depth texture at the correct resolution.
FRDGTextureMSAA SharedDepthTexture;
const bool bIsScalingTranslucency = SeparateTranslucencyDimensions.Scale != 1.0f;
if (bIsScalingTranslucency)
{
const FRDGTextureDesc Desc = FRDGTextureDesc::Create2D(
SeparateTranslucencyDimensions.Extent,
PF_DepthStencil,
FClearValueBinding::DepthFar,
TexCreate_DepthStencilTargetable | TexCreate_ShaderResource,
1,
SeparateTranslucencyDimensions.NumSamples);
SharedDepthTexture = CreateTextureMSAA(
GraphBuilder, Desc,
TEXT("Translucency.Depth"),
GFastVRamConfig.SeparateTranslucencyModulate); // TODO: this should be SeparateTranslucency, but is what the code was doing
// Downscale the depth buffer for each individual view, but shared accross all translucencies.
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
const ETranslucencyView TranslucencyView = GetTranslucencyView(View);
if (!ShouldRenderView(View, TranslucencyView))
{
continue;
}
const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetInstancedStereoViewport(View);
AddDownsampleDepthPass(
GraphBuilder, View,
FScreenPassTexture(SceneTextures.Depth.Resolve, View.ViewRect),
FScreenPassRenderTarget(SharedDepthTexture.Target, SeparateTranslucencyViewport.Rect, ViewIndex == 0 ? ERenderTargetLoadAction::EClear : ERenderTargetLoadAction::ELoad),
EDownsampleDepthFilter::Point);
}
}
else
{
// Uses the existing depth buffer for depth testing the translucency.
SharedDepthTexture = SceneTextures.Depth;
}
if (ViewFamily.AllowTranslucencyAfterDOF())
{
RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_StandardTranslucency, InstanceCullingManager);
if (GetHairStrandsComposition() == EHairStrandsCompositionType::AfterTranslucentBeforeTranslucentAfterDOF)
{
RenderHairComposition(GraphBuilder, Views, SceneTextures.Color.Target, SceneTextures.Depth.Target, SceneTextures.Velocity);
}
RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterDOF, InstanceCullingManager);
RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterDOFModulate, InstanceCullingManager);
RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_TranslucencyAfterMotionBlur, InstanceCullingManager);
}
else // Otherwise render translucent primitives in a single bucket.
{
RenderTranslucencyInner(GraphBuilder, SceneTextures, TranslucentLightingVolumeTextures, OutTranslucencyResourceMap, SharedDepthTexture, ViewsToRender, SceneColorCopyTexture, ETranslucencyPass::TPT_AllTranslucency, InstanceCullingManager);
}
bool bUpscalePostDOFTranslucency = true;
FRDGTextureRef SharedUpscaledPostDOFTranslucencyColor = nullptr;
if (bUpscalePostDOFTranslucency)
{
const FRDGTextureDesc Desc = FRDGTextureDesc::Create2D(
SceneTextures.Color.Resolve->Desc.Extent,
PF_FloatRGBA,
FClearValueBinding::Black,
TexCreate_RenderTargetable | TexCreate_ShaderResource);
SharedUpscaledPostDOFTranslucencyColor = GraphBuilder.CreateTexture(
Desc, TEXT("Translucency.PostDOF.UpscaledColor"));
}
// Upscale to full res.
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
const ETranslucencyView TranslucencyView = GetTranslucencyView(View);
if (!ShouldRenderView(View, TranslucencyView))
{
continue;
}
// Upscale the responsive AA into original depth buffer.
bool bUpscaleResponsiveAA = (
IsTemporalAccumulationBasedMethod(View.AntiAliasingMethod) &&
SharedDepthTexture.Target != SceneTextures.Depth.Target);
if (bUpscaleResponsiveAA)
{
const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetInstancedStereoViewport(View);
AddUpsampleResponsiveAAPass(
GraphBuilder,
View,
FScreenPassTexture(SharedDepthTexture.Target, SeparateTranslucencyViewport.Rect),
/* OutputDepthTexture = */ SceneTextures.Depth.Target);
}
FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, ETranslucencyPass::TPT_TranslucencyAfterDOF);
if (SharedUpscaledPostDOFTranslucencyColor && TranslucencyPassResources.IsValid() && TranslucencyPassResources.ViewRect.Size() != View.ViewRect.Size() && ITemporalUpscaler::GetMainTAAPassConfig(View) != EMainTAAPassConfig::TSR)
{
FTranslucencyComposition TranslucencyComposition;
TranslucencyComposition.Operation = FTranslucencyComposition::EOperation::UpscaleOnly;
TranslucencyComposition.SceneDepth = FScreenPassTexture(SceneTextures.Depth.Resolve, View.ViewRect);
TranslucencyComposition.OutputViewport = FScreenPassTextureViewport(SceneTextures.Depth.Resolve, View.ViewRect);
FScreenPassTexture UpscaledTranslucency = TranslucencyComposition.AddPass(
GraphBuilder, View, TranslucencyPassResources);
TranslucencyPassResources.ViewRect = UpscaledTranslucency.ViewRect;
TranslucencyPassResources.ColorTexture = FRDGTextureMSAA(UpscaledTranslucency.Texture);
TranslucencyPassResources.DepthTexture = FRDGTextureMSAA();
}
}
}
void FDeferredShadingSceneRenderer::RenderTranslucencyInner(
FRDGBuilder& GraphBuilder,
const FMinimalSceneTextures& SceneTextures,
const FTranslucencyLightingVolumeTextures& TranslucentLightingVolumeTextures,
FTranslucencyPassResourcesMap* OutTranslucencyResourceMap,
FRDGTextureMSAA SharedDepthTexture,
ETranslucencyView ViewsToRender,
FRDGTextureRef SceneColorCopyTexture,
ETranslucencyPass::Type TranslucencyPass,
FInstanceCullingManager& InstanceCullingManager)
{
if (!ShouldRenderTranslucency(TranslucencyPass))
{
return;
}
RDG_WAIT_FOR_TASKS_CONDITIONAL(GraphBuilder, IsTranslucencyWaitForTasksEnabled());
const bool bIsModulate = TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate;
const bool bDepthTest = TranslucencyPass != ETranslucencyPass::TPT_TranslucencyAfterMotionBlur;
const bool bRenderInParallel = IsParallelTranslucencyEnabled();
const bool bIsScalingTranslucency = SeparateTranslucencyDimensions.Scale < 1.0f;
const bool bRenderInSeparateTranslucency = IsSeparateTranslucencyEnabled(TranslucencyPass, SeparateTranslucencyDimensions.Scale);
// Can't reference scene color in scene textures. Scene color copy is used instead.
ESceneTextureSetupMode SceneTextureSetupMode = ESceneTextureSetupMode::All;
EnumRemoveFlags(SceneTextureSetupMode, ESceneTextureSetupMode::SceneColor);
if (bRenderInSeparateTranslucency)
{
// Create resources shared by each view (each view data is tiled into each of the render target resources)
FRDGTextureMSAA SharedColorTexture = CreatePostDOFTranslucentTexture(GraphBuilder, TranslucencyPass, SeparateTranslucencyDimensions, bIsModulate, ShaderPlatform);
for (int32 ViewIndex = 0, NumProcessedViews = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
const ETranslucencyView TranslucencyView = GetTranslucencyView(View);
if (!EnumHasAnyFlags(TranslucencyView, ViewsToRender))
{
continue;
}
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
FIntRect ScaledViewRect = GetScaledRect(View.ViewRect, SeparateTranslucencyDimensions.Scale);
const FScreenPassTextureViewport SeparateTranslucencyViewport = SeparateTranslucencyDimensions.GetInstancedStereoViewport(View);
const bool bCompositeBackToSceneColor = IsMainTranslucencyPass(TranslucencyPass) || EnumHasAnyFlags(TranslucencyView, ETranslucencyView::UnderWater);
const bool bLumenGIEnabled = GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen;
/** Separate translucency color is either composited immediately or later during post processing. If done immediately, it's because the view doesn't support
* compositing (e.g. we're rendering an underwater view) or because we're downsampling the main translucency pass. In this case, we use a local set of
* textures instead of the external ones passed in.
*/
FRDGTextureMSAA SeparateTranslucencyColorTexture = SharedColorTexture;
// NOTE: No depth test on post-motionblur translucency
FRDGTextureMSAA SeparateTranslucencyDepthTexture;
if (bDepthTest)
{
SeparateTranslucencyDepthTexture = SharedDepthTexture;
}
const ERenderTargetLoadAction SeparateTranslucencyColorLoadAction = NumProcessedViews == 0 || View.Family->bMultiGPUForkAndJoin
? ERenderTargetLoadAction::EClear
: ERenderTargetLoadAction::ELoad;
FOITData OITData = OIT::CreateOITData(GraphBuilder, View, OITPass_SeperateTranslucency);
RenderTranslucencyViewInner(
GraphBuilder,
*this,
View,
SeparateTranslucencyViewport,
SeparateTranslucencyDimensions.Scale,
SeparateTranslucencyColorTexture,
SeparateTranslucencyColorLoadAction,
SeparateTranslucencyDepthTexture.Target,
CreateTranslucentBasePassUniformBuffer(GraphBuilder, Scene, View, ViewIndex, TranslucentLightingVolumeTextures, SceneColorCopyTexture, SceneTextureSetupMode, bLumenGIEnabled, OITData),
TranslucencyPass,
!bCompositeBackToSceneColor,
bRenderInParallel,
InstanceCullingManager);
{
FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, TranslucencyPass);
TranslucencyPassResources.ViewRect = ScaledViewRect;
TranslucencyPassResources.ColorTexture = SharedColorTexture;
TranslucencyPassResources.DepthTexture = SharedDepthTexture;
}
if (OITData.PassType & OITPass_SeperateTranslucency)
{
OIT::AddOITComposePass(GraphBuilder, View, OITData, SeparateTranslucencyColorTexture.Target);
}
if (bCompositeBackToSceneColor)
{
FRDGTextureRef SeparateTranslucencyDepthResolve = nullptr;
FRDGTextureRef SceneDepthResolve = nullptr;
if (TranslucencyPass != ETranslucencyPass::TPT_TranslucencyAfterMotionBlur)
{
::AddResolveSceneDepthPass(GraphBuilder, View, SeparateTranslucencyDepthTexture);
SeparateTranslucencyDepthResolve = SeparateTranslucencyDepthTexture.Resolve;
SceneDepthResolve = SceneTextures.Depth.Resolve;
}
FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, TranslucencyPass);
FTranslucencyComposition TranslucencyComposition;
TranslucencyComposition.Operation = FTranslucencyComposition::EOperation::ComposeToExistingSceneColor;
TranslucencyComposition.SceneColor = FScreenPassTexture(SceneTextures.Color.Target, View.ViewRect);
TranslucencyComposition.SceneDepth = FScreenPassTexture(SceneTextures.Depth.Resolve, View.ViewRect);
TranslucencyComposition.OutputViewport = FScreenPassTextureViewport(SceneTextures.Depth.Resolve, View.ViewRect);
FScreenPassTexture UpscaledTranslucency = TranslucencyComposition.AddPass(
GraphBuilder, View, TranslucencyPassResources);
ensure(View.ViewRect == UpscaledTranslucency.ViewRect);
ensure(UpscaledTranslucency.Texture == SceneTextures.Color.Target);
//Invalidate.
TranslucencyPassResources = FTranslucencyPassResources();
TranslucencyPassResources.Pass = TranslucencyPass;
}
else
{
if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate)
{
FTranslucencyPassResources& TranslucencyPassResources = OutTranslucencyResourceMap->Get(ViewIndex, ETranslucencyPass::TPT_TranslucencyAfterDOF);
ensure(TranslucencyPassResources.ViewRect == ScaledViewRect);
ensure(TranslucencyPassResources.DepthTexture == SharedDepthTexture);
TranslucencyPassResources.ColorModulateTexture = SharedColorTexture;
}
else
{
check(!bIsModulate);
}
}
++NumProcessedViews;
}
}
else
{
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
const ETranslucencyView TranslucencyView = GetTranslucencyView(View);
if (!EnumHasAnyFlags(TranslucencyView, ViewsToRender))
{
continue;
}
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
const ERenderTargetLoadAction SceneColorLoadAction = ERenderTargetLoadAction::ELoad;
const FScreenPassTextureViewport Viewport(SceneTextures.Color.Target, View.ViewRect);
const float ViewportScale = 1.0f;
const bool bResolveColorTexture = false;
const bool bLumenGIEnabled = GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen;
FOITData OITData = OIT::CreateOITData(GraphBuilder, View, OITPass_RegularTranslucency);
RenderTranslucencyViewInner(
GraphBuilder,
*this,
View,
Viewport,
ViewportScale,
SceneTextures.Color,
SceneColorLoadAction,
SceneTextures.Depth.Target,
CreateTranslucentBasePassUniformBuffer(GraphBuilder, Scene, View, ViewIndex, TranslucentLightingVolumeTextures, SceneColorCopyTexture, SceneTextureSetupMode, bLumenGIEnabled, OITData),
TranslucencyPass,
bResolveColorTexture,
bRenderInParallel,
InstanceCullingManager);
if (OITData.PassType & OITPass_RegularTranslucency)
{
OIT::AddOITComposePass(GraphBuilder, View, OITData, SceneTextures.Color.Target);
}
}
}
}
TRDGUniformBufferRef<FTranslucentBasePassUniformParameters> CreateTranslucentBasePassUniformBuffer(
FRDGBuilder& GraphBuilder,
const FScene* Scene,
const FViewInfo& View,
const int32 ViewIndex,
const FTranslucencyLightingVolumeTextures& TranslucencyLightingVolumeTextures,
FRDGTextureRef SceneColorCopyTexture,
const ESceneTextureSetupMode SceneTextureSetupMode,
bool bLumenGIEnabled,
const FOITData& OITData)
{
FTranslucentBasePassUniformParameters& BasePassParameters = *GraphBuilder.AllocParameters<FTranslucentBasePassUniformParameters>();
const auto GetRDG = [&](const TRefCountPtr<IPooledRenderTarget>& PooledRenderTarget, ERDGTextureFlags Flags = ERDGTextureFlags::None)
{
return GraphBuilder.RegisterExternalTexture(PooledRenderTarget, Flags);
};
SetupSharedBasePassParameters(GraphBuilder, View, bLumenGIEnabled, BasePassParameters.Shared);
SetupSceneTextureUniformParameters(GraphBuilder, View.GetSceneTexturesChecked(), View.FeatureLevel, SceneTextureSetupMode, BasePassParameters.SceneTextures);
Strata::BindStrataForwardPasslUniformParameters(GraphBuilder, View, BasePassParameters.Strata);
const FLightSceneProxy* SelectedForwardDirectionalLightProxy = View.ForwardLightingResources.SelectedForwardDirectionalLightProxy;
SetupLightCloudTransmittanceParameters(GraphBuilder, Scene, View, SelectedForwardDirectionalLightProxy ? SelectedForwardDirectionalLightProxy->GetLightSceneInfo() : nullptr, BasePassParameters.ForwardDirLightCloudShadow);
const FRDGSystemTextures& SystemTextures = FRDGSystemTextures::Get(GraphBuilder);
// Material SSR
{
float PrevSceneColorPreExposureInvValue = 1.0f / View.PreExposure;
if (View.HZB)
{
BasePassParameters.HZBTexture = View.HZB;
BasePassParameters.HZBSampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
FRDGTextureRef PrevSceneColorTexture = SystemTextures.Black;
FIntRect PrevSceneColorViewRect = FIntRect(0, 0, 1, 1);
if (View.PrevViewInfo.CustomSSRInput.IsValid())
{
PrevSceneColorTexture = GetRDG(View.PrevViewInfo.CustomSSRInput.RT[0]);
PrevSceneColorViewRect = View.PrevViewInfo.CustomSSRInput.ViewportRect;
PrevSceneColorPreExposureInvValue = 1.0f / View.PrevViewInfo.SceneColorPreExposure;
}
else if (View.PrevViewInfo.TemporalAAHistory.IsValid())
{
PrevSceneColorTexture = GetRDG(View.PrevViewInfo.TemporalAAHistory.RT[0]);
PrevSceneColorViewRect = View.PrevViewInfo.TemporalAAHistory.ViewportRect;
PrevSceneColorPreExposureInvValue = 1.0f / View.PrevViewInfo.SceneColorPreExposure;
}
else if (View.PrevViewInfo.ScreenSpaceRayTracingInput.IsValid())
{
PrevSceneColorTexture = GetRDG(View.PrevViewInfo.ScreenSpaceRayTracingInput);
PrevSceneColorViewRect = View.PrevViewInfo.ViewRect;
PrevSceneColorPreExposureInvValue = 1.0f / View.PrevViewInfo.SceneColorPreExposure;
}
BasePassParameters.PrevSceneColor = PrevSceneColorTexture;
BasePassParameters.PrevSceneColorSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
FScreenPassTextureViewportParameters PrevSceneColorParameters = GetScreenPassTextureViewportParameters(FScreenPassTextureViewport(PrevSceneColorTexture, PrevSceneColorViewRect));
BasePassParameters.PrevSceneColorBilinearUVMin = PrevSceneColorParameters.UVViewportBilinearMin;
BasePassParameters.PrevSceneColorBilinearUVMax = PrevSceneColorParameters.UVViewportBilinearMax;
const FVector2f HZBUvFactor(
float(View.ViewRect.Width()) / float(2 * View.HZBMipmap0Size.X),
float(View.ViewRect.Height()) / float(2 * View.HZBMipmap0Size.Y)
);
const FVector4f HZBUvFactorAndInvFactorValue(
HZBUvFactor.X,
HZBUvFactor.Y,
1.0f / HZBUvFactor.X,
1.0f / HZBUvFactor.Y
);
BasePassParameters.HZBUvFactorAndInvFactor = HZBUvFactorAndInvFactorValue;
}
else
{
BasePassParameters.HZBTexture = SystemTextures.Black;
BasePassParameters.HZBSampler = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
BasePassParameters.PrevSceneColor = SystemTextures.Black;
BasePassParameters.PrevSceneColorSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
BasePassParameters.PrevSceneColorBilinearUVMin = FVector2f(0.0f, 0.0f);
BasePassParameters.PrevSceneColorBilinearUVMax = FVector2f(1.0f, 1.0f);
}
BasePassParameters.ApplyVolumetricCloudOnTransparent = 0.0f;
BasePassParameters.VolumetricCloudColor = nullptr;
BasePassParameters.VolumetricCloudDepth = nullptr;
BasePassParameters.VolumetricCloudColorSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
BasePassParameters.VolumetricCloudDepthSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
if (IsVolumetricRenderTargetEnabled() && View.ViewState)
{
TRefCountPtr<IPooledRenderTarget> VolumetricReconstructRT = View.ViewState->VolumetricCloudRenderTarget.GetDstVolumetricReconstructRT();
if (VolumetricReconstructRT.IsValid())
{
TRefCountPtr<IPooledRenderTarget> VolumetricReconstructRTDepth = View.ViewState->VolumetricCloudRenderTarget.GetDstVolumetricReconstructRTDepth();
BasePassParameters.VolumetricCloudColor = VolumetricReconstructRT->GetRHI();
BasePassParameters.VolumetricCloudDepth = VolumetricReconstructRTDepth->GetRHI();
BasePassParameters.ApplyVolumetricCloudOnTransparent = 1.0f;
}
}
if (BasePassParameters.VolumetricCloudColor == nullptr)
{
BasePassParameters.VolumetricCloudColor = GSystemTextures.BlackAlphaOneDummy->GetRHI();
BasePassParameters.VolumetricCloudDepth = GSystemTextures.BlackDummy->GetRHI();
}
FIntPoint ViewportOffset = View.ViewRect.Min;
FIntPoint ViewportExtent = View.ViewRect.Size();
// Scene render targets might not exist yet; avoids NaNs.
FIntPoint EffectiveBufferSize = View.GetSceneTexturesConfig().Extent;
EffectiveBufferSize.X = FMath::Max(EffectiveBufferSize.X, 1);
EffectiveBufferSize.Y = FMath::Max(EffectiveBufferSize.Y, 1);
if (View.PrevViewInfo.CustomSSRInput.IsValid())
{
ViewportOffset = View.PrevViewInfo.CustomSSRInput.ViewportRect.Min;
ViewportExtent = View.PrevViewInfo.CustomSSRInput.ViewportRect.Size();
EffectiveBufferSize = View.PrevViewInfo.CustomSSRInput.RT[0]->GetDesc().Extent;
}
else if (View.PrevViewInfo.TemporalAAHistory.IsValid())
{
ViewportOffset = View.PrevViewInfo.TemporalAAHistory.ViewportRect.Min;
ViewportExtent = View.PrevViewInfo.TemporalAAHistory.ViewportRect.Size();
EffectiveBufferSize = View.PrevViewInfo.TemporalAAHistory.RT[0]->GetDesc().Extent;
}
else if (View.PrevViewInfo.ScreenSpaceRayTracingInput.IsValid())
{
ViewportOffset = View.PrevViewInfo.ViewRect.Min;
ViewportExtent = View.PrevViewInfo.ViewRect.Size();
EffectiveBufferSize = View.PrevViewInfo.ScreenSpaceRayTracingInput->GetDesc().Extent;
}
FVector2f InvBufferSize(1.0f / float(EffectiveBufferSize.X), 1.0f / float(EffectiveBufferSize.Y));
FVector4f ScreenPosToPixelValue(
ViewportExtent.X * 0.5f * InvBufferSize.X,
-ViewportExtent.Y * 0.5f * InvBufferSize.Y,
(ViewportExtent.X * 0.5f + ViewportOffset.X) * InvBufferSize.X,
(ViewportExtent.Y * 0.5f + ViewportOffset.Y) * InvBufferSize.Y);
BasePassParameters.PrevScreenPositionScaleBias = ScreenPosToPixelValue;
BasePassParameters.PrevSceneColorPreExposureInv = PrevSceneColorPreExposureInvValue;
BasePassParameters.SSRQuality = ShouldRenderTranslucencyScreenSpaceReflections(View) ? GetSSRQuality() : 0;
}
// Translucency Lighting Volume
BasePassParameters.TranslucencyLightingVolume = GetTranslucencyLightingVolumeParameters(GraphBuilder, TranslucencyLightingVolumeTextures, View);
BasePassParameters.LumenParameters = GetLumenTranslucencyLightingParameters(GraphBuilder, View.LumenTranslucencyGIVolume, View.LumenFrontLayerTranslucency);
const bool bLumenGIHandlingSkylight = bLumenGIEnabled
&& BasePassParameters.LumenParameters.TranslucencyGIGridSize.Z > 0;
BasePassParameters.Shared.UseBasePassSkylight = bLumenGIHandlingSkylight ? 0 : 1;
BasePassParameters.SceneColorCopyTexture = SystemTextures.Black;
BasePassParameters.SceneColorCopySampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
if (SceneColorCopyTexture)
{
BasePassParameters.SceneColorCopyTexture = SceneColorCopyTexture;
}
BasePassParameters.EyeAdaptationTexture = GetEyeAdaptationTexture(GraphBuilder, View);
BasePassParameters.PreIntegratedGFTexture = GSystemTextures.PreintegratedGF->GetRHI();
BasePassParameters.PreIntegratedGFSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
OIT::SetOITParameters(GraphBuilder, View, BasePassParameters.OIT, OITData);
return GraphBuilder.CreateUniformBuffer(&BasePassParameters);
}
static void RenderTranslucencyViewInner(
FRDGBuilder& GraphBuilder,
const FSceneRenderer& SceneRenderer,
FViewInfo& View,
FScreenPassTextureViewport Viewport,
float ViewportScale,
FRDGTextureMSAA SceneColorTexture,
ERenderTargetLoadAction SceneColorLoadAction,
FRDGTextureRef SceneDepthTexture,
TRDGUniformBufferRef<FTranslucentBasePassUniformParameters> BasePassParameters,
ETranslucencyPass::Type TranslucencyPass,
bool bResolveColorTexture,
bool bRenderInParallel,
FInstanceCullingManager& InstanceCullingManager)
{
if (!View.ShouldRenderView())
{
return;
}
if (SceneColorLoadAction == ERenderTargetLoadAction::EClear)
{
AddClearRenderTargetPass(GraphBuilder, SceneColorTexture.Target);
}
View.BeginRenderView();
FTranslucentBasePassParameters* PassParameters = GraphBuilder.AllocParameters<FTranslucentBasePassParameters>();
PassParameters->View = GetSeparateTranslucencyViewParameters(View, Viewport.Extent, ViewportScale, TranslucencyPass);
PassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer;
PassParameters->BasePass = BasePassParameters;
PassParameters->VirtualShadowMapSamplingParameters = SceneRenderer.VirtualShadowMapArray.GetSamplingParameters(GraphBuilder);
PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneColorTexture.Target, ERenderTargetLoadAction::ELoad);
if (TranslucencyPass != ETranslucencyPass::TPT_TranslucencyAfterMotionBlur)
{
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(SceneDepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthRead_StencilWrite);
}
PassParameters->RenderTargets.ShadingRateTexture = GVRSImageManager.GetVariableRateShadingImage(GraphBuilder, SceneRenderer.ViewFamily, nullptr);
PassParameters->RenderTargets.ResolveRect = FResolveRect(Viewport.Rect);
const EMeshPass::Type MeshPass = TranslucencyPassToMeshPass(TranslucencyPass);
View.ParallelMeshDrawCommandPasses[MeshPass].BuildRenderingCommands(GraphBuilder, SceneRenderer.Scene->GPUScene, PassParameters->InstanceCullingDrawParams);
if (bRenderInParallel)
{
GraphBuilder.AddPass(
RDG_EVENT_NAME("Translucency(%s Parallel) %dx%d",
TranslucencyPassToString(TranslucencyPass),
int32(View.ViewRect.Width() * ViewportScale),
int32(View.ViewRect.Height() * ViewportScale)),
PassParameters,
ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass,
[&SceneRenderer, &View, PassParameters, ViewportScale, Viewport, TranslucencyPass](const FRDGPass* InPass, FRHICommandListImmediate& RHICmdList)
{
FRDGParallelCommandListSet ParallelCommandListSet(InPass, RHICmdList, GET_STATID(STAT_CLP_Translucency), SceneRenderer, View, FParallelCommandListBindings(PassParameters), ViewportScale);
RenderViewTranslucencyInner(RHICmdList, SceneRenderer, View, Viewport, ViewportScale, TranslucencyPass, &ParallelCommandListSet, PassParameters->InstanceCullingDrawParams);
});
}
else
{
GraphBuilder.AddPass(
RDG_EVENT_NAME("Translucency(%s) %dx%d",
TranslucencyPassToString(TranslucencyPass),
int32(View.ViewRect.Width() * ViewportScale),
int32(View.ViewRect.Height() * ViewportScale)),
PassParameters,
ERDGPassFlags::Raster,
[&SceneRenderer, &View, ViewportScale, Viewport, TranslucencyPass, PassParameters](FRHICommandList& RHICmdList)
{
RenderViewTranslucencyInner(RHICmdList, SceneRenderer, View, Viewport, ViewportScale, TranslucencyPass, nullptr, PassParameters->InstanceCullingDrawParams);
});
}
if (bResolveColorTexture)
{
AddResolveSceneColorPass(GraphBuilder, View, SceneColorTexture);
}
}
static void RenderViewTranslucencyInner(
FRHICommandList& RHICmdList,
const FSceneRenderer& SceneRenderer,
const FViewInfo& View,
const FScreenPassTextureViewport Viewport,
const float ViewportScale,
ETranslucencyPass::Type TranslucencyPass,
FRDGParallelCommandListSet* ParallelCommandListSet,
const FInstanceCullingDrawParams& InstanceCullingDrawParams)
{
FMeshPassProcessorRenderState DrawRenderState;
if (TranslucencyPass == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur)
{
// No depth test in post-motionblur translucency
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
}
else
{
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI());
}
SceneRenderer.SetStereoViewport(RHICmdList, View, ViewportScale);
if (!View.Family->UseDebugViewPS())
{
QUICK_SCOPE_CYCLE_COUNTER(RenderTranslucencyParallel_Start_FDrawSortedTransAnyThreadTask);
const EMeshPass::Type MeshPass = TranslucencyPassToMeshPass(TranslucencyPass);
View.ParallelMeshDrawCommandPasses[MeshPass].DispatchDraw(ParallelCommandListSet, RHICmdList, &InstanceCullingDrawParams);
}
}
void FParallelMeshDrawCommandPass::DispatchDraw(FParallelCommandListSet* ParallelCommandListSet, FRHICommandList& RHICmdList, const FInstanceCullingDrawParams* InstanceCullingDrawParams) const
{
TRACE_CPUPROFILER_EVENT_SCOPE(ParallelMdcDispatchDraw);
if (MaxNumDraws <= 0)
{
return;
}
FMeshDrawCommandOverrideArgs OverrideArgs;
if (InstanceCullingDrawParams)
{
OverrideArgs = GetMeshDrawCommandOverrideArgs(*InstanceCullingDrawParams);
}
if (ParallelCommandListSet)
{
const ENamedThreads::Type RenderThread = ENamedThreads::GetRenderThread();
FGraphEventArray Prereqs;
if (ParallelCommandListSet->GetPrereqs())
{
Prereqs.Append(*ParallelCommandListSet->GetPrereqs());
}
if (TaskEventRef.IsValid())
{
Prereqs.Add(TaskEventRef);
}
// Distribute work evenly to the available task graph workers based on NumEstimatedDraws.
// Every task will then adjust it's working range based on FVisibleMeshDrawCommandProcessTask results.
const int32 NumThreads = FMath::Min<int32>(FTaskGraphInterface::Get().GetNumWorkerThreads(), ParallelCommandListSet->Width);
const int32 NumTasks = FMath::Min<int32>(NumThreads, FMath::DivideAndRoundUp(MaxNumDraws, ParallelCommandListSet->MinDrawsPerCommandList));
const int32 NumDrawsPerTask = FMath::DivideAndRoundUp(MaxNumDraws, NumTasks);
for (int32 TaskIndex = 0; TaskIndex < NumTasks; TaskIndex++)
{
const int32 StartIndex = TaskIndex * NumDrawsPerTask;
const int32 NumDraws = FMath::Min(NumDrawsPerTask, MaxNumDraws - StartIndex);
checkSlow(NumDraws > 0);
FRHICommandList* CmdList = ParallelCommandListSet->NewParallelCommandList();
FGraphEventRef AnyThreadCompletionEvent = TGraphTask<FDrawVisibleMeshCommandsAnyThreadTask>::CreateTask(&Prereqs, RenderThread)
.ConstructAndDispatchWhenReady(*CmdList, TaskContext.InstanceCullingContext, TaskContext.MeshDrawCommands, TaskContext.MinimalPipelineStatePassSet,
OverrideArgs,
TaskContext.InstanceFactor,
TaskIndex, NumTasks);
ParallelCommandListSet->AddParallelCommandList(CmdList, AnyThreadCompletionEvent, NumDraws);
}
}
else
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_MeshPassDrawImmediate);
WaitForMeshPassSetupTask(IsInActualRenderingThread() ? EWaitThread::Render : EWaitThread::Task);
if (TaskContext.bUseGPUScene)
{
if (TaskContext.MeshDrawCommands.Num() > 0)
{
TaskContext.InstanceCullingContext.SubmitDrawCommands(
TaskContext.MeshDrawCommands,
TaskContext.MinimalPipelineStatePassSet,
OverrideArgs,
0,
TaskContext.MeshDrawCommands.Num(),
TaskContext.InstanceFactor,
RHICmdList);
}
}
else
{
SubmitMeshDrawCommandsRange(TaskContext.MeshDrawCommands, TaskContext.MinimalPipelineStatePassSet, nullptr, 0, 0, TaskContext.bDynamicInstancing, 0, TaskContext.MeshDrawCommands.Num(), TaskContext.InstanceFactor, RHICmdList);
}
}
}
Shader Code
void FPixelShaderInOut_MainPS(
FVertexFactoryInterpolantsVSToPS Interpolants,
FSharedBasePassInterpolants BasePassInterpolants,
in FPixelShaderIn In,
inout FPixelShaderOut Out)
{
const uint EyeIndex = 0;
ResolvedView = ResolveView();
float4 OutVelocity = 0;
float4 OutGBufferD = 0;
float4 OutGBufferE = 0;
FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(Interpolants, In.SvPosition);
FPixelMaterialInputs PixelMaterialInputs;
float LightmapVTPageTableResult = ( float )0.0f;
{
CalcMaterialParameters(MaterialParameters, PixelMaterialInputs, In.SvPosition, In.bIsFrontFace);
}
const bool bEditorWeightedZBuffering = false;
if (!bEditorWeightedZBuffering)
{
GetMaterialCoverageAndClipping(MaterialParameters, PixelMaterialInputs);
}
const float Dither = InterleavedGradientNoise(MaterialParameters.SvPosition.xy, View_StateFrameIndexMod8);
float3 BaseColor = GetMaterialBaseColor(PixelMaterialInputs);
float Metallic = GetMaterialMetallic(PixelMaterialInputs);
float Specular = GetMaterialSpecular(PixelMaterialInputs);
float Roughness = GetMaterialRoughness(PixelMaterialInputs);
float Anisotropy = GetMaterialAnisotropy(PixelMaterialInputs);
uint ShadingModel = GetMaterialShadingModel(PixelMaterialInputs);
float Opacity = GetMaterialOpacity(PixelMaterialInputs);
float MaterialAO = GetMaterialAmbientOcclusion(PixelMaterialInputs);
float3 SubsurfaceColor = 0;
float SubsurfaceProfile = 0;
float DBufferOpacity = 1.0f;
const float BaseMaterialCoverageOverWater = Opacity;
const float WaterVisibility = 1.0 - BaseMaterialCoverageOverWater;
float3 VolumetricLightmapBrickTextureUVs;
FGBufferData GBuffer = (FGBufferData)0;
GBuffer.GBufferAO = MaterialAO;
GBuffer.PerObjectGBufferData = GetPrimitive_PerObjectGBufferData(MaterialParameters.PrimitiveId);
GBuffer.Depth = MaterialParameters.ScreenPosition.w;
GBuffer.PrecomputedShadowFactors = GetPrecomputedShadowMasks(LightmapVTPageTableResult, Interpolants, MaterialParameters, VolumetricLightmapBrickTextureUVs);
SetGBufferForShadingModel(
GBuffer,
MaterialParameters,
Opacity,
BaseColor,
Metallic,
Specular,
Roughness,
Anisotropy,
SubsurfaceColor,
SubsurfaceProfile,
Dither,
ShadingModel
);
const bool bChecker = CheckerFromPixelPos(MaterialParameters.SvPosition.xy);
if(GBuffer.ShadingModelID == 12 )
{
float3 FinalDiffuseColor = GBuffer.BaseColor;
}
if(GBuffer.ShadingModelID == 12 )
{
GBuffer.SpecularColor = SubsurfaceColor;
}
else
{
GBuffer.SpecularColor = ComputeF0(Specular, BaseColor, Metallic);
}
if(GBuffer.ShadingModelID == 12 )
{
GBuffer.DiffuseColor = BaseColor;
}
else
{
GBuffer.DiffuseColor = BaseColor - BaseColor * Metallic;
}
{
GBuffer.DiffuseColor = GBuffer.DiffuseColor * View_DiffuseOverrideParameter.w + View_DiffuseOverrideParameter.xyz;
GBuffer.SpecularColor = GBuffer.SpecularColor * View_SpecularOverrideParameter.w + View_SpecularOverrideParameter.xyz;
}
if (View_RenderingReflectionCaptureMask)
{
EnvBRDFApproxFullyRough(GBuffer.DiffuseColor, GBuffer.SpecularColor);
}
float3 InputBentNormal = MaterialParameters.WorldNormal;
[branch] if( GBuffer.ShadingModelID == 4 && 0 )
{
const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 4) - (512.0/255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal);
InputBentNormal = OctahedronToUnitVector(oct1);
}
const FShadingOcclusion ShadingOcclusion = ApplyBentNormal(MaterialParameters.CameraVector, InputBentNormal, GetWorldBentNormalZero(MaterialParameters), GBuffer.Roughness, MaterialAO);
GBuffer.GBufferAO = AOMultiBounce( Luminance( GBuffer.SpecularColor ), ShadingOcclusion.SpecOcclusion ).g;
GBuffer.DiffuseIndirectSampleOcclusion = GetDiffuseIndirectSampleOcclusion(GBuffer, MaterialParameters.CameraVector, MaterialParameters.WorldNormal, GetWorldBentNormalZero(MaterialParameters), In.SvPosition.xy, MaterialAO);
float3 DiffuseColor = 0;
float3 Color = 0;
float IndirectIrradiance = 0;
float3 ColorSeparateSpecular = 0;
float3 ColorSeparateEmissive = 0;
float3 DiffuseIndirectLighting = 0;
float3 SubsurfaceIndirectLighting = 0;
bool bSeparateWaterMainDirLightLuminance = ( 0 ) > 0 && View_SeparateWaterMainDirLightLuminance > 0.0f;
float3 SeparatedWaterMainDirLightLuminance = float3(0, 0, 0);
float3 DiffuseDir = ShadingOcclusion.BentNormal;
float3 DiffuseColorForIndirect = GBuffer.DiffuseColor;
const bool bEvaluateBackface = GetShadingModelRequiresBackfaceLighting(GBuffer.ShadingModelID);
GetPrecomputedIndirectLightingAndSkyLight(MaterialParameters, Interpolants, BasePassInterpolants, LightmapVTPageTableResult, bEvaluateBackface, DiffuseDir, VolumetricLightmapBrickTextureUVs, DiffuseIndirectLighting, SubsurfaceIndirectLighting, IndirectIrradiance);
float IndirectOcclusion = 1.0f;
float2 NearestResolvedDepthScreenUV = 0;
float DirectionalLightShadow = 1.0f;
float DirectionalLightCloudShadow = 1.0f;
DiffuseColor += (DiffuseIndirectLighting * DiffuseColorForIndirect + SubsurfaceIndirectLighting * SubsurfaceColor) * AOMultiBounce( GBuffer.BaseColor, ShadingOcclusion.DiffOcclusion );
float4 HeightFogging = BasePassInterpolants.VertexFog;
float4 Fogging = HeightFogging;
if ( TranslucentBasePass_Shared_Fog_ApplyVolumetricFog > 0)
{
float3 VolumeUV = ComputeVolumeUV(MaterialParameters.AbsoluteWorldPosition, ResolvedView.WorldToClip);
Fogging = CombineVolumetricFog(HeightFogging, VolumeUV, EyeIndex, GBuffer.Depth);
}
float3 Emissive = 0;
if (GBuffer.ShadingModelID == 1 || GBuffer.ShadingModelID == 2 )
{
Color += GetTranslucencyVolumeLighting(MaterialParameters, PixelMaterialInputs, BasePassInterpolants, GBuffer, IndirectIrradiance);
}
float3 GBufferDiffuseColor = GBuffer.DiffuseColor;
float3 GBufferSpecularColor = GBuffer.SpecularColor;
EnvBRDFApproxFullyRough(GBufferDiffuseColor, GBufferSpecularColor);
Color = lerp(Color, GBufferDiffuseColor, View_UnlitViewmodeMask);
Emissive = GetMaterialEmissive(PixelMaterialInputs);
float3 OutOfBoundsMaskLuminance = 0;
[branch]
if (View_OutOfBoundsMask > 0)
{
FPrimitiveSceneData PrimitiveData = GetPrimitiveData(MaterialParameters);
float3 ObjectBounds =
float3(
PrimitiveData.ObjectBoundsX,
PrimitiveData.ObjectBoundsY,
PrimitiveData.ObjectBoundsZ
);
if (any(abs(LWCToFloat(LWCSubtract(MaterialParameters.AbsoluteWorldPosition, PrimitiveData.ObjectWorldPosition))) > ObjectBounds + 1))
{
float Gradient = LWCFrac(LWCDivide(LWCDot(MaterialParameters.AbsoluteWorldPosition, float3(.577f, .577f, .577f)), 500.0f));
OutOfBoundsMaskLuminance = lerp(float3(1,1,0), float3(0,1,1), Gradient.xxx > .5f);
Emissive = OutOfBoundsMaskLuminance;
Opacity = 1;
}
}
Color += DiffuseColor;
Color += Emissive;
bool bStrataSubsurfaceEnable = false;
Out.MRT[0] = float4 (Color * Fogging.a + Fogging.rgb, Opacity);
Out.MRT[0] = ( Out.MRT[0] ) ;
Out.MRT[1] = OutVelocity;
if(bEditorWeightedZBuffering)
{
Out.MRT[0].a = 1;
clip(Out.MRT[0].a - GetMaterialOpacityMaskClipValue());
}
const float ViewPreExposure = View_PreExposure;
Out.MRT[0].rgb *= ViewPreExposure;
}
/** Calculates lighting for translucency. */
float3 GetTranslucencyVolumeLighting(
FMaterialPixelParameters MaterialParameters,
FPixelMaterialInputs PixelMaterialInputs,
FBasePassInterpolantsVSToPS BasePassInterpolants,
FGBufferData GBuffer,
float IndirectIrradiance)
{
float4 VolumeLighting;
float3 InterpolatedLighting = 0;
float3 InnerVolumeUVs;
float3 OuterVolumeUVs;
float FinalLerpFactor;
ComputeVolumeUVs(MaterialParameters.WorldPosition_CamRelative, MaterialParameters.LightingPositionOffset, InnerVolumeUVs, OuterVolumeUVs, FinalLerpFactor);
#if TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_DIRECTIONAL
GetVolumeLightingDirectional(float4(BasePassInterpolants.AmbientLightingVector, 1), BasePassInterpolants.DirectionalLightingVector, MaterialParameters.WorldNormal, GBuffer.DiffuseColor, InterpolatedLighting, VolumeLighting);
#elif TRANSLUCENCY_LIGHTING_VOLUMETRIC_PERVERTEX_NONDIRECTIONAL
GetVolumeLightingNonDirectional(float4(BasePassInterpolants.AmbientLightingVector, 1), GBuffer.DiffuseColor, InterpolatedLighting, VolumeLighting);
#elif TRANSLUCENCY_LIGHTING_VOLUMETRIC_DIRECTIONAL || TRANSLUCENCY_LIGHTING_SURFACE_LIGHTINGVOLUME
float4 AmbientLightingVector = GetAmbientLightingVectorFromTranslucentLightingVolume(InnerVolumeUVs, OuterVolumeUVs, FinalLerpFactor);
float3 DirectionalLightingVector = GetDirectionalLightingVectorFromTranslucentLightingVolume(InnerVolumeUVs, OuterVolumeUVs, FinalLerpFactor);
GetVolumeLightingDirectional(AmbientLightingVector, DirectionalLightingVector, MaterialParameters.WorldNormal, GBuffer.DiffuseColor, InterpolatedLighting, VolumeLighting);
#elif TRANSLUCENCY_LIGHTING_VOLUMETRIC_NONDIRECTIONAL
float4 AmbientLightingVector = GetAmbientLightingVectorFromTranslucentLightingVolume(InnerVolumeUVs, OuterVolumeUVs, FinalLerpFactor);
GetVolumeLightingNonDirectional(AmbientLightingVector, GBuffer.DiffuseColor, InterpolatedLighting, VolumeLighting);
#endif
return InterpolatedLighting;
}
void GetVolumeLightingNonDirectional(float4 AmbientLightingVector, float3 DiffuseColor, inout float3 InterpolatedLighting, out float4 VolumeLighting)
{
// Normal is not taken into account with non directional lighting, and only the ambient term of the SH coefficients are needed
FOneBandSHVectorRGB TranslucentLighting;
TranslucentLighting.R.V.x = AmbientLightingVector.r;
TranslucentLighting.G.V.x = AmbientLightingVector.g;
TranslucentLighting.B.V.x = AmbientLightingVector.b;
FOneBandSHVector DiffuseTransferSH = CalcDiffuseTransferSH1(1);
VolumeLighting = float4(DotSH1(TranslucentLighting, DiffuseTransferSH), AmbientLightingVector.a);
InterpolatedLighting = DiffuseColor * VolumeLighting.rgb;
}
FOneBandSHVector CalcDiffuseTransferSH1(half Exponent)
{
FOneBandSHVector Result = SHBasisFunction1();
// These formula are scaling factors for each SH band that convolve a SH with the circularly symmetric function
// max(0,cos(theta))^Exponent
half L0 = 2 * PI / (1 + 1 * Exponent );
// Multiply the coefficients in each band with the appropriate band scaling factor.
Result.V *= L0;
return Result;
}
FOneBandSHVector SHBasisFunction1()
{
FOneBandSHVector Result;
// These are derived from simplifying SHBasisFunction in C++
Result.V = 0.282095f;
return Result;
}
float4 GetAmbientLightingVectorFromTranslucentLightingVolume(float3 InnerVolumeUVs, float3 OuterVolumeUVs, float FinalLerpFactor)
{
// Lookup the inner and outer cascade ambient lighting values
float4 InnerLighting = Texture3DSampleLevel(TranslucentBasePass.TranslucencyLightingVolumeAmbientInner, SharedAmbientInnerSampler, InnerVolumeUVs, 0);
float4 OuterLighting = Texture3DSampleLevel(TranslucentBasePass.TranslucencyLightingVolumeAmbientOuter, SharedAmbientOuterSampler, OuterVolumeUVs, 0);
// Lerp between cascades
return lerp(OuterLighting, InnerLighting, FinalLerpFactor);
}
void GetPrecomputedIndirectLightingAndSkyLight(
FMaterialPixelParameters MaterialParameters,
FVertexFactoryInterpolantsVSToPS Interpolants,
FSharedBasePassInterpolants BasePassInterpolants,
float LightmapVTPageTableResult,
bool bEvaluateBackface,
float3 DiffuseDir,
float3 VolumetricLightmapBrickTextureUVs,
out float3 OutDiffuseLighting,
out float3 OutSubsurfaceLighting,
out float OutIndirectIrradiance)
{
OutIndirectIrradiance = 0;
OutDiffuseLighting = 0;
OutSubsurfaceLighting = 0;
float2 SkyOcclusionUV = ( float2 )0;
uint SkyOcclusionDataIndex = 0u;
OutDiffuseLighting *= View_PrecomputedIndirectLightingColorScale;
OutSubsurfaceLighting *= View_PrecomputedIndirectLightingColorScale;
float3 SkyDiffuseLighting;
float3 SkySubsurfaceLighting;
GetSkyLighting(MaterialParameters, LightmapVTPageTableResult, bEvaluateBackface, DiffuseDir, SkyOcclusionUV, SkyOcclusionDataIndex, VolumetricLightmapBrickTextureUVs, SkyDiffuseLighting, SkySubsurfaceLighting);
OutSubsurfaceLighting += SkySubsurfaceLighting;
OutDiffuseLighting += SkyDiffuseLighting;
}
void GetSkyLighting(FMaterialPixelParameters MaterialParameters, float LightmapVTPageTableResult, bool bEvaluateBackface, float3 WorldNormal, float2 LightmapUV, uint LightmapDataIndex, float3 SkyOcclusionUV3D, out float3 OutDiffuseLighting, out float3 OutSubsurfaceLighting)
{
OutDiffuseLighting = 0;
OutSubsurfaceLighting = 0;
if (IsLumenTranslucencyGIEnabled())
{
FTwoBandSHVectorRGB TranslucencyGISH = GetTranslucencyGIVolumeLighting(MaterialParameters.AbsoluteWorldPosition, ResolvedView.WorldToClip, true);
FOneBandSHVectorRGB TranslucencyGISH1;
TranslucencyGISH1.R.V = TranslucencyGISH.R.V.x;
TranslucencyGISH1.G.V = TranslucencyGISH.G.V.x;
TranslucencyGISH1.B.V = TranslucencyGISH.B.V.x;
FOneBandSHVector DiffuseTransferSH = CalcDiffuseTransferSH1(1);
OutDiffuseLighting += max(float3(0,0,0), DotSH1(TranslucencyGISH1, DiffuseTransferSH)) / PI;
}
}
FTwoBandSHVectorRGB GetTranslucencyGIVolumeLighting(FLWCVector3 WorldPosition, FLWCInverseMatrix WorldToClip, bool bTemporalFiltered)
{
float3 VolumeUV = ComputeTranslucencyGIVolumeUV(WorldPosition, WorldToClip);
float3 AmbientLightingVector;
float3 DirectionalLightingVector;
if (bTemporalFiltered)
{
AmbientLightingVector = Texture3DSampleLevel( TranslucentBasePass_TranslucencyGIVolumeHistory0 , TranslucentBasePass_TranslucencyGIVolumeSampler , VolumeUV, 0).xyz;
DirectionalLightingVector = Texture3DSampleLevel( TranslucentBasePass_TranslucencyGIVolumeHistory1 , TranslucentBasePass_TranslucencyGIVolumeSampler , VolumeUV, 0).xyz;
}
else
{
AmbientLightingVector = Texture3DSampleLevel( TranslucentBasePass_TranslucencyGIVolume0 , TranslucentBasePass_TranslucencyGIVolumeSampler , VolumeUV, 0).xyz;
DirectionalLightingVector = Texture3DSampleLevel( TranslucentBasePass_TranslucencyGIVolume1 , TranslucentBasePass_TranslucencyGIVolumeSampler , VolumeUV, 0).xyz;
}
FTwoBandSHVectorRGB TranslucentLighting;
TranslucentLighting.R.V.x = AmbientLightingVector.r;
TranslucentLighting.G.V.x = AmbientLightingVector.g;
TranslucentLighting.B.V.x = AmbientLightingVector.b;
float3 NormalizedAmbientColor = AmbientLightingVector.rgb / ( Luminance( AmbientLightingVector.rgb ) + 0.00001f );
TranslucentLighting.R.V.yzw = DirectionalLightingVector.rgb * NormalizedAmbientColor.r;
TranslucentLighting.G.V.yzw = DirectionalLightingVector.rgb * NormalizedAmbientColor.g;
TranslucentLighting.B.V.yzw = DirectionalLightingVector.rgb * NormalizedAmbientColor.b;
return TranslucentLighting;
}