Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironment.cpp
Luke Thatcher 22b2ad89ea Copying //UE4/Dev-Console to //UE4/Dev-Main (Source: //UE4/Dev-Console @ 3378220)
#lockdown Nick.Penwarden

==========================
MAJOR FEATURES + CHANGES
==========================

Change 3301794 on 2017/02/14 by Josh.Adams

	Fixed a crash with clothing on platforms that don't support NV_CLOTH

Change 3302696 on 2017/02/14 by Chad.Garyet

	adding dev-console json

Change 3306418 on 2017/02/16 by Ben.Woodhouse

	Fix prepass/basepass zfighting, caused by bad vertex welding in depth-only indexbuffer. Requires bumping the staticmesh DDC key
	Duplicated from Fortnite/Main CL 3302965
	#jira UE-34332

Change 3308922 on 2017/02/17 by Josh.Adams

	- Disabled the game analytics anon usage data sent to Epic on the console platforms

Change 3311506 on 2017/02/20 by Keith.Judge

	Replicate fix for FD3D12UniqueDescriptorTable leak in async compute contexts from another branch.

Change 3313445 on 2017/02/20 by Josh.Adams

	- Various Vulkan fixes:
	  - Compiles in Linux
	  - Many cubemap bugs squashed
	  - Changed the scratch reflection cubemap clear to SetRenderTargestsAndClear, instead of SetRenderTarget() / Clear()
	  - Added compute fences

Change 3314916 on 2017/02/21 by Josh.Adams

	- Fixed an issue with 4 and 8 vertex instanced particles using the wrong VertexFactory objects (D3D didn't even need separate VFs due to the VertexDecl updating the stride at draw call time)

Change 3315398 on 2017/02/21 by Ben.Woodhouse

	Fix GPUTestbed packaging

Change 3316340 on 2017/02/22 by Ben.Woodhouse

	Duplicate hotfix from Release-4.15:
	CL 3316322
	Fix for GPU Cubemap copy crash - Guard for invalid indices before marking cubemap indices as removed
	#jira UE-42165

Change 3317345 on 2017/02/22 by Ben.Woodhouse

	Integrate from //UE4/Main/...@3316239

Change 3319186 on 2017/02/23 by Josh.Adams

	Added /VIRTUALIZEDIRECTX option to XgConsole for XGE shader compiling to work  on remote machines without DX installed

Change 3323514 on 2017/02/27 by Chad.Garyet

	adding populate ddc for dev-console, removing RDU agent type

Change 3335889 on 2017/03/07 by Luke.Thatcher

	[CONSOLE] [STREAMS] [^] Merge //UE4/Main (CL 3335229) to //UE4/Dev-Console

	#tests Build Win64 Editor, run QAGame editor, Launch on PS4.

Change 3336550 on 2017/03/07 by Ben.Woodhouse

	Duplicate CL 3336456
	#jira UE-42468
	Fix a bug in the rendertargetpool handling of fastVRAM targets, reported on UDN

Change 3340385 on 2017/03/09 by Ben.Woodhouse

	Optimized fastVRAM layout and configurability. CVars can be configured based title rendering requirements and resolution
	With these changes, we try to store the GBuffer in Fast VRAM if possible. Transient/non perf critical surfaces are now disabled by default
	In content w/ dynamic lighting @ 900p we see a 1.8ms gain. In RenderTestMap QAGame @ 1080p we see 0.4ms gains (further improvements may be possible with additional tweaking).

Change 3355982 on 2017/03/21 by Ben.Woodhouse

	Duplicate from CL 3354688:
	Fix async SSAO not actually running asynchronously. This was because bHZBBeforeBasePass  was set to false even though we had a full prepass (EDepthDrawingMode::DDM_AllOpaque), so we didn't process it until after the basepass.
	This saved 0.6ms in GPUTestbed

Change 3356166 on 2017/03/21 by Ben.Woodhouse

	Duplicate from 3347033
	Subsurface postprocess optimization, courtesy of Mike O'Connor at Iron Galaxy Studios.

	Add a branch to reduce bandwidth. Halved the cost of the setup pass according to PIX (0.3ms to 0.15ms)

Change 3360243 on 2017/03/23 by Luke.Thatcher

	[CONSOLE] [STREAMS] [^] Merge //UE4/Main (CL 3358685) to //UE4/Dev-Console

	#tests Build Win64 Editor, run FortGPUTestbed editor, Launch on PS4.

Change 3365746 on 2017/03/27 by Joe.Barnes

	- Handle NULL source data.
	- Log failed surround conversion.

Change 3368022 on 2017/03/28 by Ben.Woodhouse

	Cherry pick reflection capture hotfix from release-4.15 CL 3365830:
	Fixed reflection capture crash when repeatedly adding/removing captures
	Previously we used an array of indices (CubemapIndicesRemovedSinceLastRealloc) to keep track of indices which had been removed, however this caused issues when those indices were reused by subsequent allocations before the array was reallocated
	The new method uses a simple bitfield to track usage (one bit per cubemap slot index).
	Also fixed order(N^2) index search in the index allocator - now just a fast bit scan

	#jira UE-42165
	#jira UE-42911

Change 3371568 on 2017/03/30 by Luke.Thatcher

	[CONSOLE] [STREAMS] [^] Merging //UE4/Dev-Main (CL 3371054) to Dev-Console (//UE4/Dev-Console)

Change 3372780 on 2017/03/30 by Joe.Barnes

	Add support for multi-channel ADPCM encoding. Format based on game side ADPCM decompressor.

Change 3374847 on 2017/03/31 by Ben.Woodhouse

	Fix shipping warning
	#jira UE-43522

Change 3376442 on 2017/04/03 by Ben.Woodhouse

	Fix FortGPUTestbed animnotify cook errors (delete the offending animnotifies)

[CL 3378288 by Luke Thatcher in Main branch]
2017-04-04 09:10:29 -04:00

1511 lines
63 KiB
C++

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
Reflection Environment - feature that provides HDR glossy reflections on any surfaces, leveraging precomputation to prefilter cubemaps of the scene
=============================================================================*/
#include "ReflectionEnvironment.h"
#include "Stats/Stats.h"
#include "HAL/IConsoleManager.h"
#include "RHI.h"
#include "UniformBuffer.h"
#include "ShaderParameters.h"
#include "RendererInterface.h"
#include "Shader.h"
#include "StaticBoundShaderState.h"
#include "SceneUtils.h"
#include "RHIStaticStates.h"
#include "PostProcess/SceneRenderTargets.h"
#include "GlobalShader.h"
#include "SceneRenderTargetParameters.h"
#include "DeferredShadingRenderer.h"
#include "BasePassRendering.h"
#include "ScenePrivate.h"
#include "PostProcess/SceneFilterRendering.h"
#include "PostProcess/PostProcessing.h"
#include "PostProcess/ScreenSpaceReflections.h"
#include "LightRendering.h"
#include "LightPropagationVolumeBlendable.h"
#include "PipelineStateCache.h"
DECLARE_FLOAT_COUNTER_STAT(TEXT("Reflection Environment"), Stat_GPU_ReflectionEnvironment, STATGROUP_GPU);
/** Tile size for the reflection environment compute shader, tweaked for PS4. */
const int32 GReflectionEnvironmentTileSizeX = 8;
const int32 GReflectionEnvironmentTileSizeY = 8;
extern TAutoConsoleVariable<int32> CVarLPVMixing;
static TAutoConsoleVariable<int32> CVarReflectionEnvironment(
TEXT("r.ReflectionEnvironment"),
1,
TEXT("Whether to render the reflection environment feature, which implements local reflections through Reflection Capture actors.\n")
TEXT(" 0: off\n")
TEXT(" 1: on and blend with scene (default)")
TEXT(" 2: on and overwrite scene (only in non-shipping builds)"),
ECVF_RenderThreadSafe | ECVF_Scalability);
int32 GReflectionEnvironmentLightmapMixing = 1;
FAutoConsoleVariableRef CVarReflectionEnvironmentLightmapMixing(
TEXT("r.ReflectionEnvironmentLightmapMixing"),
GReflectionEnvironmentLightmapMixing,
TEXT("Whether to mix indirect specular from reflection captures with indirect diffuse from lightmaps for rough surfaces."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
int32 GReflectionEnvironmentLightmapMixBasedOnRoughness = 1;
FAutoConsoleVariableRef CVarReflectionEnvironmentLightmapMixBasedOnRoughness(
TEXT("r.ReflectionEnvironmentLightmapMixBasedOnRoughness"),
GReflectionEnvironmentLightmapMixBasedOnRoughness,
TEXT("Whether to reduce lightmap mixing with reflection captures for very smooth surfaces. This is useful to make sure reflection captures match SSR / planar reflections in brightness."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
float GReflectionEnvironmentBeginMixingRoughness = .1f;
FAutoConsoleVariableRef CVarReflectionEnvironmentBeginMixingRoughness(
TEXT("r.ReflectionEnvironmentBeginMixingRoughness"),
GReflectionEnvironmentBeginMixingRoughness,
TEXT("Min roughness value at which to begin mixing reflection captures with lightmap indirect diffuse."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
float GReflectionEnvironmentEndMixingRoughness = .3f;
FAutoConsoleVariableRef CVarReflectionEnvironmentEndMixingRoughness(
TEXT("r.ReflectionEnvironmentEndMixingRoughness"),
GReflectionEnvironmentEndMixingRoughness,
TEXT("Min roughness value at which to end mixing reflection captures with lightmap indirect diffuse."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
int32 GReflectionEnvironmentLightmapMixLargestWeight = 10000;
FAutoConsoleVariableRef CVarReflectionEnvironmentLightmapMixLargestWeight(
TEXT("r.ReflectionEnvironmentLightmapMixLargestWeight"),
GReflectionEnvironmentLightmapMixLargestWeight,
TEXT("When set to 1 can be used to clamp lightmap mixing such that only darkening from lightmaps are applied to reflection captures."),
ECVF_Scalability | ECVF_RenderThreadSafe
);
static TAutoConsoleVariable<int32> CVarDoTiledReflections(
TEXT("r.DoTiledReflections"),
1,
TEXT("Compute Reflection Environment with Tiled compute shader..\n")
TEXT(" 0: off\n")
TEXT(" 1: on (default)"),
ECVF_RenderThreadSafe);
static TAutoConsoleVariable<float> CVarSkySpecularOcclusionStrength(
TEXT("r.SkySpecularOcclusionStrength"),
1,
TEXT("Strength of skylight specular occlusion from DFAO (default is 1.0)"),
ECVF_RenderThreadSafe);
// to avoid having direct access from many places
static int GetReflectionEnvironmentCVar()
{
int32 RetVal = CVarReflectionEnvironment.GetValueOnAnyThread();
#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
// Disabling the debug part of this CVar when in shipping
if (RetVal == 2)
{
RetVal = 1;
}
#endif
return RetVal;
}
FVector GetReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight()
{
float RoughnessMixingRange = 1.0f / FMath::Max(GReflectionEnvironmentEndMixingRoughness - GReflectionEnvironmentBeginMixingRoughness, .001f);
if (GReflectionEnvironmentLightmapMixing == 0)
{
return FVector(0, 0, GReflectionEnvironmentLightmapMixLargestWeight);
}
if (GReflectionEnvironmentEndMixingRoughness == 0.0f && GReflectionEnvironmentBeginMixingRoughness == 0.0f)
{
// Make sure a Roughness of 0 results in full mixing when disabling roughness-based mixing
return FVector(0, 1, GReflectionEnvironmentLightmapMixLargestWeight);
}
if (!GReflectionEnvironmentLightmapMixBasedOnRoughness)
{
return FVector(0, 1, GReflectionEnvironmentLightmapMixLargestWeight);
}
return FVector(RoughnessMixingRange, -GReflectionEnvironmentBeginMixingRoughness * RoughnessMixingRange, GReflectionEnvironmentLightmapMixLargestWeight);
}
bool IsReflectionEnvironmentAvailable(ERHIFeatureLevel::Type InFeatureLevel)
{
return (InFeatureLevel >= ERHIFeatureLevel::SM4) && (GetReflectionEnvironmentCVar() != 0);
}
bool IsReflectionCaptureAvailable()
{
static IConsoleVariable* AllowStaticLightingVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.AllowStaticLighting"));
return (!AllowStaticLightingVar || AllowStaticLightingVar->GetInt() != 0);
}
void FReflectionEnvironmentCubemapArray::InitDynamicRHI()
{
if (GetFeatureLevel() >= ERHIFeatureLevel::SM5)
{
const int32 NumReflectionCaptureMips = FMath::CeilLogTwo(CubemapSize) + 1;
ReleaseCubeArray();
FPooledRenderTargetDesc Desc(
FPooledRenderTargetDesc::CreateCubemapDesc(
CubemapSize,
// Alpha stores sky mask
PF_FloatRGBA,
FClearValueBinding::None,
TexCreate_None,
TexCreate_None,
false,
// Cubemap array of 1 produces a regular cubemap, so guarantee it will be allocated as an array
FMath::Max<uint32>(MaxCubemaps, 2),
NumReflectionCaptureMips
)
);
Desc.AutoWritable = false;
FRHICommandListImmediate& RHICmdList = FRHICommandListExecutor::GetImmediateCommandList();
// Allocate TextureCubeArray for the scene's reflection captures
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, ReflectionEnvs, TEXT("ReflectionEnvs"));
}
}
void FReflectionEnvironmentCubemapArray::ReleaseCubeArray()
{
// it's unlikely we can reuse the TextureCubeArray so when we release it we want to really remove it
GRenderTargetPool.FreeUnusedResource(ReflectionEnvs);
}
void FReflectionEnvironmentCubemapArray::ReleaseDynamicRHI()
{
ReleaseCubeArray();
}
void FReflectionEnvironmentSceneData::ResizeCubemapArrayGPU(uint32 InMaxCubemaps, int32 InCubemapSize)
{
check(IsInRenderingThread());
// If the cubemap array isn't setup yet then no copying/reallocation is necessary. Just go through the old path
if (!CubemapArray.IsInitialized())
{
CubemapArraySlotsUsed.Init(false, InMaxCubemaps);
CubemapArray.UpdateMaxCubemaps(InMaxCubemaps, InCubemapSize);
return;
}
// Generate a remapping table for the elements
TArray<int32> IndexRemapping;
int32 Count = 0;
for (int i = 0; i < CubemapArray.GetMaxCubemaps(); i++)
{
if (CubemapArraySlotsUsed[i] )
{
IndexRemapping.Add(Count);
Count++;
}
else
{
IndexRemapping.Add(-1);
}
}
// Reset the CubemapArraySlotsUsed array (we'll recompute it below)
CubemapArraySlotsUsed.Init(false, InMaxCubemaps);
// Spin through the AllocatedReflectionCaptureState map and remap the indices based on the LUT
TArray<const UReflectionCaptureComponent*> Components;
AllocatedReflectionCaptureState.GetKeys(Components);
int32 UsedCubemapCount = 0;
for (int32 i=0; i<Components.Num(); i++ )
{
FCaptureComponentSceneState* ComponentStatePtr = AllocatedReflectionCaptureState.Find(Components[i]);
check(ComponentStatePtr->CaptureIndex < IndexRemapping.Num());
int32 NewIndex = IndexRemapping[ComponentStatePtr->CaptureIndex];
CubemapArraySlotsUsed[NewIndex] = true;
ComponentStatePtr->CaptureIndex = NewIndex;
check(ComponentStatePtr->CaptureIndex > -1);
UsedCubemapCount = FMath::Max(UsedCubemapCount, ComponentStatePtr->CaptureIndex + 1);
}
// Clear elements in the remapping array which are outside the range of the used components (these were allocated but not used)
for (int i = 0; i < IndexRemapping.Num(); i++)
{
if (IndexRemapping[i] >= UsedCubemapCount)
{
IndexRemapping[i] = -1;
}
}
CubemapArray.ResizeCubemapArrayGPU(InMaxCubemaps, InCubemapSize, IndexRemapping);
}
void FReflectionEnvironmentCubemapArray::ResizeCubemapArrayGPU(uint32 InMaxCubemaps, int32 InCubemapSize, const TArray<int32>& IndexRemapping)
{
check(IsInRenderingThread());
check(GetFeatureLevel() >= ERHIFeatureLevel::SM5);
check(IsInitialized());
check(InCubemapSize == CubemapSize);
// Take a reference to the old cubemap array and then release it to prevent it getting destroyed during InitDynamicRHI
TRefCountPtr<IPooledRenderTarget> OldReflectionEnvs = ReflectionEnvs;
ReflectionEnvs = nullptr;
int OldMaxCubemaps = MaxCubemaps;
MaxCubemaps = InMaxCubemaps;
InitDynamicRHI();
FTextureRHIRef TexRef = OldReflectionEnvs->GetRenderTargetItem().TargetableTexture;
FRHICommandListImmediate& RHICmdList = FRHICommandListExecutor::GetImmediateCommandList();
const int32 NumMips = FMath::CeilLogTwo(InCubemapSize) + 1;
{
SCOPED_DRAW_EVENT(RHICmdList, ReflectionEnvironment_ResizeCubemapArray);
SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ReflectionEnvironment)
// Copy the cubemaps, remapping the elements as necessary
FResolveParams ResolveParams;
ResolveParams.Rect = FResolveRect();
for (int32 SourceCubemapIndex = 0; SourceCubemapIndex < OldMaxCubemaps; SourceCubemapIndex++)
{
int32 DestCubemapIndex = IndexRemapping[SourceCubemapIndex];
if (DestCubemapIndex != -1)
{
ResolveParams.SourceArrayIndex = SourceCubemapIndex;
ResolveParams.DestArrayIndex = DestCubemapIndex;
check(SourceCubemapIndex < OldMaxCubemaps);
check(DestCubemapIndex < (int32)MaxCubemaps);
for (int Face = 0; Face < 6; Face++)
{
ResolveParams.CubeFace = (ECubeFace)Face;
for (int Mip = 0; Mip < NumMips; Mip++)
{
ResolveParams.MipIndex = Mip;
//@TODO: We should use an explicit copy method for this rather than CopyToResolveTarget, but that doesn't exist right now.
// For now, we'll just do this on RHIs where we know CopyToResolveTarget does the right thing. In future we should look to
// add a a new RHI method
check(GRHISupportsResolveCubemapFaces);
RHICmdList.CopyToResolveTarget(OldReflectionEnvs->GetRenderTargetItem().ShaderResourceTexture, ReflectionEnvs->GetRenderTargetItem().ShaderResourceTexture, true, ResolveParams);
}
}
}
}
}
GRenderTargetPool.FreeUnusedResource(OldReflectionEnvs);
}
void FReflectionEnvironmentCubemapArray::UpdateMaxCubemaps(uint32 InMaxCubemaps, int32 InCubemapSize)
{
MaxCubemaps = InMaxCubemaps;
CubemapSize = InCubemapSize;
// Reallocate the cubemap array
if (IsInitialized())
{
UpdateRHI();
}
else
{
InitResource();
}
}
class FDistanceFieldAOSpecularOcclusionParameters
{
public:
void Bind(const FShaderParameterMap& ParameterMap)
{
BentNormalAOTexture.Bind(ParameterMap, TEXT("BentNormalAOTexture"));
BentNormalAOSampler.Bind(ParameterMap, TEXT("BentNormalAOSampler"));
ApplyBentNormalAO.Bind(ParameterMap, TEXT("ApplyBentNormalAO"));
InvSkySpecularOcclusionStrength.Bind(ParameterMap, TEXT("InvSkySpecularOcclusionStrength"));
OcclusionTintAndMinOcclusion.Bind(ParameterMap, TEXT("OcclusionTintAndMinOcclusion"));
}
template<typename ShaderRHIParamRef, typename TRHICmdList>
void SetParameters(TRHICmdList& RHICmdList, const ShaderRHIParamRef& ShaderRHI, const TRefCountPtr<IPooledRenderTarget>& DynamicBentNormalAO, float SkySpecularOcclusionStrength, const FVector4& OcclusionTintAndMinOcclusionValue)
{
FTextureRHIParamRef BentNormalAO = GWhiteTexture->TextureRHI;
bool bApplyBentNormalAO = false;
if (DynamicBentNormalAO)
{
BentNormalAO = DynamicBentNormalAO->GetRenderTargetItem().ShaderResourceTexture;
bApplyBentNormalAO = true;
}
SetTextureParameter(RHICmdList, ShaderRHI, BentNormalAOTexture, BentNormalAOSampler, TStaticSamplerState<SF_Point>::GetRHI(), BentNormalAO);
SetShaderValue(RHICmdList, ShaderRHI, ApplyBentNormalAO, bApplyBentNormalAO ? 1.0f : 0.0f);
SetShaderValue(RHICmdList, ShaderRHI, InvSkySpecularOcclusionStrength, 1.0f / FMath::Max(SkySpecularOcclusionStrength, .1f));
SetShaderValue(RHICmdList, ShaderRHI, OcclusionTintAndMinOcclusion, OcclusionTintAndMinOcclusionValue);
}
friend FArchive& operator<<(FArchive& Ar,FDistanceFieldAOSpecularOcclusionParameters& P)
{
Ar << P.BentNormalAOTexture << P.BentNormalAOSampler << P.ApplyBentNormalAO << P.InvSkySpecularOcclusionStrength << P.OcclusionTintAndMinOcclusion;
return Ar;
}
private:
FShaderResourceParameter BentNormalAOTexture;
FShaderResourceParameter BentNormalAOSampler;
FShaderParameter ApplyBentNormalAO;
FShaderParameter InvSkySpecularOcclusionStrength;
FShaderParameter OcclusionTintAndMinOcclusion;
};
struct FReflectionCaptureSortData
{
uint32 Guid;
int32 CaptureIndex;
FVector4 PositionAndRadius;
FVector4 CaptureProperties;
FMatrix BoxTransform;
FVector4 BoxScales;
FVector4 CaptureOffsetAndAverageBrightness;
FTexture* SM4FullHDRCubemap;
bool operator < (const FReflectionCaptureSortData& Other) const
{
if( PositionAndRadius.W != Other.PositionAndRadius.W )
{
return PositionAndRadius.W < Other.PositionAndRadius.W;
}
else
{
return Guid < Other.Guid;
}
}
};
IMPLEMENT_UNIFORM_BUFFER_STRUCT(FReflectionCaptureData,TEXT("ReflectionCapture"));
/** Compute shader that does tiled deferred culling of reflection captures, then sorts and composites them. */
class FReflectionEnvironmentTiledDeferredCS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FReflectionEnvironmentTiledDeferredCS,Global)
public:
static bool ShouldCache(EShaderPlatform Platform)
{
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEX"), GReflectionEnvironmentTileSizeX);
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEY"), GReflectionEnvironmentTileSizeY);
OutEnvironment.SetDefine(TEXT("MAX_CAPTURES"), GMaxNumReflectionCaptures);
OutEnvironment.CompilerFlags.Add(CFLAG_StandardOptimization);
FForwardLightingParameters::ModifyCompilationEnvironment(Platform, OutEnvironment);
}
FReflectionEnvironmentTiledDeferredCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
DeferredParameters.Bind(Initializer.ParameterMap);
ReflectionCubemap.Bind(Initializer.ParameterMap,TEXT("ReflectionCubemap"));
ReflectionCubemapSampler.Bind(Initializer.ParameterMap,TEXT("ReflectionCubemapSampler"));
ScreenSpaceReflections.Bind(Initializer.ParameterMap, TEXT("ScreenSpaceReflections"));
InSceneColor.Bind(Initializer.ParameterMap, TEXT("InSceneColor"));
OutSceneColor.Bind(Initializer.ParameterMap, TEXT("OutSceneColor"));
NumCaptures.Bind(Initializer.ParameterMap, TEXT("NumCaptures"));
ViewDimensionsParameter.Bind(Initializer.ParameterMap, TEXT("ViewDimensions"));
PreIntegratedGF.Bind(Initializer.ParameterMap, TEXT("PreIntegratedGF"));
PreIntegratedGFSampler.Bind(Initializer.ParameterMap, TEXT("PreIntegratedGFSampler"));
SkyLightParameters.Bind(Initializer.ParameterMap);
SpecularOcclusionParameters.Bind(Initializer.ParameterMap);
ForwardLightingParameters.Bind(Initializer.ParameterMap);
}
FReflectionEnvironmentTiledDeferredCS()
{
}
void SetParameters(
FRHIAsyncComputeCommandListImmediate& RHICmdList,
const FViewInfo& View,
FTextureRHIParamRef SSRTexture,
FUnorderedAccessViewRHIParamRef OutSceneColorUAV,
const TRefCountPtr<IPooledRenderTarget>& DynamicBentNormalAO
)
{
const FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
DeferredParameters.Set(RHICmdList, ShaderRHI, View);
FScene* Scene = (FScene*)View.Family->Scene;
check(Scene->ReflectionSceneData.CubemapArray.IsValid());
check(Scene->ReflectionSceneData.CubemapArray.GetRenderTarget().IsValid());
FSceneRenderTargetItem& CubemapArray = Scene->ReflectionSceneData.CubemapArray.GetRenderTarget();
SetTextureParameter(
RHICmdList,
ShaderRHI,
ReflectionCubemap,
ReflectionCubemapSampler,
TStaticSamplerState<SF_Trilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI(),
CubemapArray.ShaderResourceTexture);
SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceReflections, SSRTexture );
SetTextureParameter(RHICmdList, ShaderRHI, InSceneColor, FSceneRenderTargets::Get(RHICmdList).GetSceneColor()->GetRenderTargetItem().ShaderResourceTexture );
RHICmdList.TransitionResource(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EGfxToCompute, OutSceneColorUAV);
OutSceneColor.SetTexture(RHICmdList, ShaderRHI, NULL, OutSceneColorUAV);
SetShaderValue(RHICmdList, ShaderRHI, ViewDimensionsParameter, View.ViewRect);
SetUniformBufferParameter(RHICmdList, ShaderRHI, GetUniformBufferParameter<FReflectionCaptureData>(), View.ReflectionCaptureUniformBuffer);
SetShaderValue(RHICmdList, ShaderRHI, NumCaptures, View.NumBoxReflectionCaptures + View.NumSphereReflectionCaptures);
SetTextureParameter(RHICmdList, ShaderRHI, PreIntegratedGF, PreIntegratedGFSampler, TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), GSystemTextures.PreintegratedGF->GetRenderTargetItem().ShaderResourceTexture);
SkyLightParameters.SetParameters(RHICmdList, ShaderRHI, Scene, View.Family->EngineShowFlags.SkyLighting);
const float MinOcclusion = Scene->SkyLight ? Scene->SkyLight->MinOcclusion : 0;
const FVector OcclusionTint = Scene->SkyLight ? (const FVector&)Scene->SkyLight->OcclusionTint : FVector::ZeroVector;
SpecularOcclusionParameters.SetParameters(RHICmdList, ShaderRHI, DynamicBentNormalAO, CVarSkySpecularOcclusionStrength.GetValueOnRenderThread(), FVector4(OcclusionTint, MinOcclusion));
ForwardLightingParameters.Set(RHICmdList, ShaderRHI, View);
}
void UnsetParameters(FRHIAsyncComputeCommandListImmediate& RHICmdList, FUnorderedAccessViewRHIParamRef OutSceneColorUAV)
{
const FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
OutSceneColor.UnsetUAV(RHICmdList, ShaderRHI);
}
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << DeferredParameters;
Ar << ReflectionCubemap;
Ar << ReflectionCubemapSampler;
Ar << ScreenSpaceReflections;
Ar << InSceneColor;
Ar << OutSceneColor;
Ar << NumCaptures;
Ar << ViewDimensionsParameter;
Ar << PreIntegratedGF;
Ar << PreIntegratedGFSampler;
Ar << SkyLightParameters;
Ar << SpecularOcclusionParameters;
Ar << ForwardLightingParameters;
return bShaderHasOutdatedParameters;
}
private:
FDeferredPixelShaderParameters DeferredParameters;
FShaderResourceParameter ReflectionCubemap;
FShaderResourceParameter ReflectionCubemapSampler;
FShaderResourceParameter ScreenSpaceReflections;
FShaderResourceParameter InSceneColor;
FRWShaderParameter OutSceneColor;
FShaderParameter NumCaptures;
FShaderParameter ViewDimensionsParameter;
FShaderResourceParameter PreIntegratedGF;
FShaderResourceParameter PreIntegratedGFSampler;
FSkyLightReflectionParameters SkyLightParameters;
FDistanceFieldAOSpecularOcclusionParameters SpecularOcclusionParameters;
FForwardLightingParameters ForwardLightingParameters;
};
template< uint32 bUseLightmaps, uint32 bHasSkyLight, uint32 bBoxCapturesOnly, uint32 bSphereCapturesOnly, uint32 bSupportDFAOIndirectOcclusion >
class TReflectionEnvironmentTiledDeferredCS : public FReflectionEnvironmentTiledDeferredCS
{
DECLARE_SHADER_TYPE(TReflectionEnvironmentTiledDeferredCS, Global);
/** Default constructor. */
TReflectionEnvironmentTiledDeferredCS() {}
public:
TReflectionEnvironmentTiledDeferredCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FReflectionEnvironmentTiledDeferredCS(Initializer)
{}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
FReflectionEnvironmentTiledDeferredCS::ModifyCompilationEnvironment(Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("USE_LIGHTMAPS"), bUseLightmaps);
OutEnvironment.SetDefine(TEXT("ENABLE_SKY_LIGHT"), bHasSkyLight);
OutEnvironment.SetDefine(TEXT("REFLECTION_COMPOSITE_HAS_BOX_CAPTURES"), bBoxCapturesOnly);
OutEnvironment.SetDefine(TEXT("REFLECTION_COMPOSITE_HAS_SPHERE_CAPTURES"), bSphereCapturesOnly);
OutEnvironment.SetDefine(TEXT("SUPPORT_DFAO_INDIRECT_OCCLUSION"), bSupportDFAOIndirectOcclusion);
}
};
// Typedef is necessary because the C preprocessor thinks the comma in the template parameter list is a comma in the macro parameter list.
#define IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(A, B, C, D, E) \
typedef TReflectionEnvironmentTiledDeferredCS<A,B,C,D,E> TReflectionEnvironmentTiledDeferredCS##A##B##C##D##E; \
IMPLEMENT_SHADER_TYPE(template<>,TReflectionEnvironmentTiledDeferredCS##A##B##C##D##E,TEXT("ReflectionEnvironmentComputeShaders"),TEXT("ReflectionEnvironmentTiledDeferredMain"),SF_Compute)
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 0, 0, 0, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 0, 0, 1, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 0, 1, 0, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 0, 1, 1, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 1, 0, 0, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 1, 0, 1, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 1, 1, 0, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 1, 1, 1, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 0, 0, 0, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 0, 0, 1, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 0, 1, 0, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 0, 1, 1, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 1, 0, 0, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 1, 0, 1, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 1, 1, 0, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 1, 1, 1, 0);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 0, 0, 0, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 0, 0, 1, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 0, 1, 0, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 0, 1, 1, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 1, 0, 0, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 1, 0, 1, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 1, 1, 0, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 1, 1, 1, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 0, 0, 0, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 0, 0, 1, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 0, 1, 0, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 0, 1, 1, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 1, 0, 0, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 1, 0, 1, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 1, 1, 0, 1);
IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 1, 1, 1, 1);
template< uint32 bSSR, uint32 bReflectionEnv, uint32 bSkylight, uint32 bSupportDFAOIndirectOcclusion >
class FReflectionApplyPS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FReflectionApplyPS, Global);
public:
static bool ShouldCache(EShaderPlatform Platform)
{
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("APPLY_SSR"), bSSR);
OutEnvironment.SetDefine(TEXT("APPLY_REFLECTION_ENV"), bReflectionEnv);
OutEnvironment.SetDefine(TEXT("APPLY_SKYLIGHT"), bSkylight);
OutEnvironment.SetDefine(TEXT("SUPPORT_DFAO_INDIRECT_OCCLUSION"), bSupportDFAOIndirectOcclusion);
}
/** Default constructor. */
FReflectionApplyPS() {}
/** Initialization constructor. */
FReflectionApplyPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
DeferredParameters.Bind(Initializer.ParameterMap);
SkyLightParameters.Bind(Initializer.ParameterMap);
ReflectionEnvTexture.Bind(Initializer.ParameterMap,TEXT("ReflectionEnvTexture"));
ReflectionEnvSampler.Bind(Initializer.ParameterMap,TEXT("ReflectionEnvSampler"));
ScreenSpaceReflectionsTexture.Bind(Initializer.ParameterMap,TEXT("ScreenSpaceReflectionsTexture"));
ScreenSpaceReflectionsSampler.Bind(Initializer.ParameterMap,TEXT("ScreenSpaceReflectionsSampler"));
PreIntegratedGF.Bind(Initializer.ParameterMap, TEXT("PreIntegratedGF"));
PreIntegratedGFSampler.Bind(Initializer.ParameterMap, TEXT("PreIntegratedGFSampler"));
SpecularOcclusionParameters.Bind(Initializer.ParameterMap);
}
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, FTextureRHIParamRef ReflectionEnv, FTextureRHIParamRef ScreenSpaceReflections, const TRefCountPtr<IPooledRenderTarget>& DynamicBentNormalAO)
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
DeferredParameters.Set(RHICmdList, ShaderRHI, View);
SkyLightParameters.SetParameters(RHICmdList, ShaderRHI, (FScene*)View.Family->Scene, true);
SetTextureParameter(RHICmdList, ShaderRHI, ReflectionEnvTexture, ReflectionEnvSampler, TStaticSamplerState<SF_Point>::GetRHI(), ReflectionEnv );
SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceReflectionsTexture, ScreenSpaceReflectionsSampler, TStaticSamplerState<SF_Point>::GetRHI(), ScreenSpaceReflections );
SetTextureParameter(RHICmdList, ShaderRHI, PreIntegratedGF, PreIntegratedGFSampler, TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), GSystemTextures.PreintegratedGF->GetRenderTargetItem().ShaderResourceTexture );
FScene* Scene = (FScene*)View.Family->Scene;
const float MinOcclusion = Scene->SkyLight ? Scene->SkyLight->MinOcclusion : 0;
const FVector OcclusionTint = Scene->SkyLight ? (const FVector&)Scene->SkyLight->OcclusionTint : FVector::ZeroVector;
SpecularOcclusionParameters.SetParameters(RHICmdList, ShaderRHI, DynamicBentNormalAO, CVarSkySpecularOcclusionStrength.GetValueOnRenderThread(), FVector4(OcclusionTint, MinOcclusion));
}
// FShader interface.
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << DeferredParameters;
Ar << SkyLightParameters;
Ar << ReflectionEnvTexture;
Ar << ReflectionEnvSampler;
Ar << ScreenSpaceReflectionsTexture;
Ar << ScreenSpaceReflectionsSampler;
Ar << PreIntegratedGF;
Ar << PreIntegratedGFSampler;
Ar << SpecularOcclusionParameters;
return bShaderHasOutdatedParameters;
}
private:
FDeferredPixelShaderParameters DeferredParameters;
FSkyLightReflectionParameters SkyLightParameters;
FShaderResourceParameter ReflectionEnvTexture;
FShaderResourceParameter ReflectionEnvSampler;
FShaderResourceParameter ScreenSpaceReflectionsTexture;
FShaderResourceParameter ScreenSpaceReflectionsSampler;
FShaderResourceParameter PreIntegratedGF;
FShaderResourceParameter PreIntegratedGFSampler;
FDistanceFieldAOSpecularOcclusionParameters SpecularOcclusionParameters;
};
// Typedef is necessary because the C preprocessor thinks the comma in the template parameter list is a comma in the macro parameter list.
#define IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(A, B, C, D) \
typedef FReflectionApplyPS<A,B,C,D> FReflectionApplyPS##A##B##C##D; \
IMPLEMENT_SHADER_TYPE(template<>,FReflectionApplyPS##A##B##C##D,TEXT("ReflectionEnvironmentShaders"),TEXT("ReflectionApplyPS"),SF_Pixel);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(0,0,0,0);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(0,0,1,0);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(0,1,0,0);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(0,1,1,0);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(1,0,0,0);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(1,0,1,0);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(1,1,0,0);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(1,1,1,0);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(0,0,0,1);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(0,0,1,1);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(0,1,0,1);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(0,1,1,1);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(1,0,0,1);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(1,0,1,1);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(1,1,0,1);
IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(1,1,1,1);
class FReflectionCaptureSpecularBouncePS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FReflectionCaptureSpecularBouncePS, Global);
static bool ShouldCache(EShaderPlatform Platform)
{
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Platform,OutEnvironment);
}
/** Default constructor. */
FReflectionCaptureSpecularBouncePS() {}
public:
FDeferredPixelShaderParameters DeferredParameters;
/** Initialization constructor. */
FReflectionCaptureSpecularBouncePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
DeferredParameters.Bind(Initializer.ParameterMap);
}
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View)
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
DeferredParameters.Set(RHICmdList, ShaderRHI, View);
}
// FShader interface.
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << DeferredParameters;
return bShaderHasOutdatedParameters;
}
};
IMPLEMENT_SHADER_TYPE(,FReflectionCaptureSpecularBouncePS,TEXT("ReflectionEnvironmentShaders"),TEXT("SpecularBouncePS"),SF_Pixel);
template<bool bSphereCapture>
class TStandardDeferredReflectionPS : public FGlobalShader
{
DECLARE_SHADER_TYPE(TStandardDeferredReflectionPS, Global);
public:
static bool ShouldCache(EShaderPlatform Platform)
{
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment);
OutEnvironment.SetDefine(TEXT("SPHERE_CAPTURE"), (uint32)bSphereCapture);
OutEnvironment.SetDefine(TEXT("BOX_CAPTURE"), (uint32)!bSphereCapture);
}
/** Default constructor. */
TStandardDeferredReflectionPS() {}
/** Initialization constructor. */
TStandardDeferredReflectionPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
CapturePositionAndRadius.Bind(Initializer.ParameterMap, TEXT("CapturePositionAndRadius"));
CaptureProperties.Bind(Initializer.ParameterMap, TEXT("CaptureProperties"));
CaptureBoxTransform.Bind(Initializer.ParameterMap, TEXT("CaptureBoxTransform"));
CaptureBoxScales.Bind(Initializer.ParameterMap, TEXT("CaptureBoxScales"));
CaptureOffsetAndAverageBrightness.Bind(Initializer.ParameterMap, TEXT("CaptureOffsetAndAverageBrightness"));
CaptureArrayIndex.Bind(Initializer.ParameterMap, TEXT("CaptureArrayIndex"));
ReflectionEnvironmentColorTexture.Bind(Initializer.ParameterMap, TEXT("ReflectionEnvironmentColorTexture"));
ReflectionEnvironmentColorTextureArray.Bind(Initializer.ParameterMap, TEXT("ReflectionEnvironmentColorTextureArray"));
ReflectionEnvironmentColorSampler.Bind(Initializer.ParameterMap, TEXT("ReflectionEnvironmentColorSampler"));
DeferredParameters.Bind(Initializer.ParameterMap);
}
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FReflectionCaptureSortData& SortData)
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
if (View.GetFeatureLevel() >= ERHIFeatureLevel::SM5)
{
FScene* Scene = (FScene*)View.Family->Scene;
check(Scene->ReflectionSceneData.CubemapArray.IsValid());
check(Scene->ReflectionSceneData.CubemapArray.GetRenderTarget().IsValid());
FSceneRenderTargetItem& CubemapArray = Scene->ReflectionSceneData.CubemapArray.GetRenderTarget();
SetTextureParameter(RHICmdList, ShaderRHI, ReflectionEnvironmentColorTextureArray, ReflectionEnvironmentColorSampler, TStaticSamplerState<SF_Trilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), CubemapArray.ShaderResourceTexture);
SetShaderValue(RHICmdList, ShaderRHI, CaptureArrayIndex, SortData.CaptureIndex);
}
else
{
SetTextureParameter(RHICmdList, ShaderRHI, ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, TStaticSamplerState<SF_Trilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), SortData.SM4FullHDRCubemap->TextureRHI);
}
DeferredParameters.Set(RHICmdList, ShaderRHI, View);
SetShaderValue(RHICmdList, ShaderRHI, CapturePositionAndRadius, SortData.PositionAndRadius);
SetShaderValue(RHICmdList, ShaderRHI, CaptureProperties, SortData.CaptureProperties);
SetShaderValue(RHICmdList, ShaderRHI, CaptureBoxTransform, SortData.BoxTransform);
SetShaderValue(RHICmdList, ShaderRHI, CaptureBoxScales, SortData.BoxScales);
SetShaderValue(RHICmdList, ShaderRHI, CaptureOffsetAndAverageBrightness, SortData.CaptureOffsetAndAverageBrightness);
}
// FShader interface.
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << CapturePositionAndRadius;
Ar << CaptureProperties;
Ar << CaptureBoxTransform;
Ar << CaptureBoxScales;
Ar << CaptureOffsetAndAverageBrightness;
Ar << CaptureArrayIndex;
Ar << ReflectionEnvironmentColorTexture;
Ar << ReflectionEnvironmentColorTextureArray;
Ar << ReflectionEnvironmentColorSampler;
Ar << DeferredParameters;
return bShaderHasOutdatedParameters;
}
private:
FShaderParameter CapturePositionAndRadius;
FShaderParameter CaptureProperties;
FShaderParameter CaptureBoxTransform;
FShaderParameter CaptureBoxScales;
FShaderParameter CaptureOffsetAndAverageBrightness;
FShaderParameter CaptureArrayIndex;
FShaderResourceParameter ReflectionEnvironmentColorTexture;
FShaderResourceParameter ReflectionEnvironmentColorTextureArray;
FShaderResourceParameter ReflectionEnvironmentColorSampler;
FDeferredPixelShaderParameters DeferredParameters;
};
IMPLEMENT_SHADER_TYPE(template<>,TStandardDeferredReflectionPS<true>,TEXT("ReflectionEnvironmentShaders"),TEXT("StandardDeferredReflectionPS"),SF_Pixel);
IMPLEMENT_SHADER_TYPE(template<>,TStandardDeferredReflectionPS<false>,TEXT("ReflectionEnvironmentShaders"),TEXT("StandardDeferredReflectionPS"),SF_Pixel);
void FDeferredShadingSceneRenderer::RenderReflectionCaptureSpecularBounceForAllViews(FRHICommandListImmediate& RHICmdList, FGraphicsPipelineStateInitializer& GraphicsPSOInit)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
SceneContext.BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EUninitializedColorExistingDepth, FExclusiveDepthStencil::DepthRead_StencilWrite);
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
GraphicsPSOInit.RasterizerState = TStaticRasterizerState< FM_Solid, CM_None >::GetRHI();
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState< false, CF_Always >::GetRHI();
GraphicsPSOInit.BlendState = TStaticBlendState< CW_RGB, BO_Add, BF_One, BF_One >::GetRHI();
auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
TShaderMapRef< FPostProcessVS > VertexShader(ShaderMap);
TShaderMapRef< FReflectionCaptureSpecularBouncePS > PixelShader(ShaderMap);
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader);
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader);
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
for (int32 ViewIndex = 0, Num = Views.Num(); ViewIndex < Num; ViewIndex++)
{
const FViewInfo& View = Views[ViewIndex];
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
PixelShader->SetParameters(RHICmdList, View);
DrawRectangle(
RHICmdList,
0, 0,
View.ViewRect.Width(), View.ViewRect.Height(),
0, 0,
View.ViewRect.Width(), View.ViewRect.Height(),
FIntPoint(View.ViewRect.Width(), View.ViewRect.Height()),
SceneContext.GetBufferSizeXY(),
*VertexShader,
EDRF_UseTriangleOptimization);
}
ResolveSceneColor(RHICmdList);
}
bool FDeferredShadingSceneRenderer::ShouldDoReflectionEnvironment() const
{
const ERHIFeatureLevel::Type SceneFeatureLevel = Scene->GetFeatureLevel();
return IsReflectionEnvironmentAvailable(SceneFeatureLevel)
&& Scene->ReflectionSceneData.RegisteredReflectionCaptures.Num()
&& ViewFamily.EngineShowFlags.ReflectionEnvironment
&& (SceneFeatureLevel == ERHIFeatureLevel::SM4 || Scene->ReflectionSceneData.CubemapArray.IsValid());
}
void GatherAndSortReflectionCaptures(const FViewInfo& View, const FScene* Scene, TArray<FReflectionCaptureSortData>& OutSortData, int32& OutNumBoxCaptures, int32& OutNumSphereCaptures, float& OutFurthestReflectionCaptureDistance)
{
OutSortData.Reset(Scene->ReflectionSceneData.RegisteredReflectionCaptures.Num());
OutNumBoxCaptures = 0;
OutNumSphereCaptures = 0;
OutFurthestReflectionCaptureDistance = 1000;
const int32 MaxCubemaps = Scene->ReflectionSceneData.CubemapArray.GetMaxCubemaps();
if (View.Family->EngineShowFlags.ReflectionEnvironment)
{
// Pack only visible reflection captures into the uniform buffer, each with an index to its cubemap array entry
//@todo - view frustum culling
for (int32 ReflectionProxyIndex = 0; ReflectionProxyIndex < Scene->ReflectionSceneData.RegisteredReflectionCaptures.Num() && OutSortData.Num() < GMaxNumReflectionCaptures; ReflectionProxyIndex++)
{
FReflectionCaptureProxy* CurrentCapture = Scene->ReflectionSceneData.RegisteredReflectionCaptures[ReflectionProxyIndex];
// Find the cubemap index this component was allocated with
const FCaptureComponentSceneState* ComponentStatePtr = Scene->ReflectionSceneData.AllocatedReflectionCaptureState.Find(CurrentCapture->Component);
if (ComponentStatePtr)
{
int32 CubemapIndex = ComponentStatePtr->CaptureIndex;
check(CubemapIndex < MaxCubemaps);
FReflectionCaptureSortData NewSortEntry;
NewSortEntry.CaptureIndex = CubemapIndex;
NewSortEntry.SM4FullHDRCubemap = NULL;
NewSortEntry.Guid = CurrentCapture->Guid;
NewSortEntry.PositionAndRadius = FVector4(CurrentCapture->Position, CurrentCapture->InfluenceRadius);
float ShapeTypeValue = (float)CurrentCapture->Shape;
NewSortEntry.CaptureProperties = FVector4(CurrentCapture->Brightness, CubemapIndex, ShapeTypeValue, 0);
NewSortEntry.CaptureOffsetAndAverageBrightness = FVector4(CurrentCapture->CaptureOffset, CurrentCapture->AverageBrightness);
if (CurrentCapture->Shape == EReflectionCaptureShape::Plane)
{
//planes count as boxes in the compute shader.
++OutNumBoxCaptures;
NewSortEntry.BoxTransform = FMatrix(
FPlane(CurrentCapture->ReflectionPlane),
FPlane(CurrentCapture->ReflectionXAxisAndYScale),
FPlane(0, 0, 0, 0),
FPlane(0, 0, 0, 0));
NewSortEntry.BoxScales = FVector4(0);
}
else if (CurrentCapture->Shape == EReflectionCaptureShape::Sphere)
{
++OutNumSphereCaptures;
}
else
{
++OutNumBoxCaptures;
NewSortEntry.BoxTransform = CurrentCapture->BoxTransform;
NewSortEntry.BoxScales = FVector4(CurrentCapture->BoxScales, CurrentCapture->BoxTransitionDistance);
}
const FSphere BoundingSphere(CurrentCapture->Position, CurrentCapture->InfluenceRadius);
const float Distance = View.ViewMatrices.GetViewMatrix().TransformPosition(BoundingSphere.Center).Z + BoundingSphere.W;
OutFurthestReflectionCaptureDistance = FMath::Max(OutFurthestReflectionCaptureDistance, Distance);
OutSortData.Add(NewSortEntry);
}
}
}
OutSortData.Sort();
}
void FDeferredShadingSceneRenderer::SetupReflectionCaptureBuffers(FViewInfo& View, FRHICommandListImmediate& RHICmdList)
{
if (View.GetFeatureLevel() >= ERHIFeatureLevel::SM5)
{
TArray<FReflectionCaptureSortData> SortData;
GatherAndSortReflectionCaptures(View, Scene, SortData, View.NumBoxReflectionCaptures, View.NumSphereReflectionCaptures, View.FurthestReflectionCaptureDistance);
FReflectionCaptureData SamplePositionsBuffer;
for (int32 CaptureIndex = 0; CaptureIndex < SortData.Num(); CaptureIndex++)
{
SamplePositionsBuffer.PositionAndRadius[CaptureIndex] = SortData[CaptureIndex].PositionAndRadius;
SamplePositionsBuffer.CaptureProperties[CaptureIndex] = SortData[CaptureIndex].CaptureProperties;
SamplePositionsBuffer.CaptureOffsetAndAverageBrightness[CaptureIndex] = SortData[CaptureIndex].CaptureOffsetAndAverageBrightness;
SamplePositionsBuffer.BoxTransform[CaptureIndex] = SortData[CaptureIndex].BoxTransform;
SamplePositionsBuffer.BoxScales[CaptureIndex] = SortData[CaptureIndex].BoxScales;
}
View.ReflectionCaptureUniformBuffer = TUniformBufferRef<FReflectionCaptureData>::CreateUniformBufferImmediate(SamplePositionsBuffer, UniformBuffer_SingleFrame);
}
}
template<bool bSuportDFAOIndirectOcclusion>
FReflectionEnvironmentTiledDeferredCS* SelectReflectionEnvironmentTiledDeferredCSInner(TShaderMap<FGlobalShaderType>* ShaderMap, bool bUseLightmaps, bool bHasSkyLight, bool bHasBoxCaptures, bool bHasSphereCaptures)
{
FReflectionEnvironmentTiledDeferredCS* ComputeShader = nullptr;
if (bUseLightmaps)
{
if (bHasSkyLight)
{
if (bHasBoxCaptures && bHasSphereCaptures)
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 1, 1, 1, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
else if (bHasBoxCaptures)
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 1, 1, 0, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
else if (bHasSphereCaptures)
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 1, 0, 1, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
else
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 1, 0, 0, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
}
else
{
if (bHasBoxCaptures && bHasSphereCaptures)
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 0, 1, 1, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
else if (bHasBoxCaptures)
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 0, 1, 0, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
else if (bHasSphereCaptures)
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 0, 0, 1, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
else
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 0, 0, 0, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
}
}
else
{
if (bHasSkyLight)
{
if (bHasBoxCaptures && bHasSphereCaptures)
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 1, 1, 1, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
else if (bHasBoxCaptures)
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 1, 1, 0, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
else if (bHasSphereCaptures)
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 1, 0, 1, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
else
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 1, 0, 0, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
}
else
{
if (bHasBoxCaptures && bHasSphereCaptures)
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 0, 1, 1, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
else if (bHasBoxCaptures)
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 0, 1, 0, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
else if (bHasSphereCaptures)
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 0, 0, 1, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
else
{
ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 0, 0, 0, bSuportDFAOIndirectOcclusion> >(ShaderMap);
}
}
}
check(ComputeShader);
return ComputeShader;
}
FReflectionEnvironmentTiledDeferredCS* SelectReflectionEnvironmentTiledDeferredCS(TShaderMap<FGlobalShaderType>* ShaderMap, bool bUseLightmaps, bool bHasSkyLight, bool bHasBoxCaptures, bool bHasSphereCaptures, bool bSuportDFAOIndirectOcclusion)
{
if (bSuportDFAOIndirectOcclusion)
{
return SelectReflectionEnvironmentTiledDeferredCSInner<true>(ShaderMap, bUseLightmaps, bHasSkyLight, bHasBoxCaptures, bHasSphereCaptures);
}
else
{
return SelectReflectionEnvironmentTiledDeferredCSInner<false>(ShaderMap, bUseLightmaps, bHasSkyLight, bHasBoxCaptures, bHasSphereCaptures);
}
}
void FDeferredShadingSceneRenderer::RenderTiledDeferredImageBasedReflections(FRHICommandListImmediate& RHICmdList, const TRefCountPtr<IPooledRenderTarget>& DynamicBentNormalAO, TRefCountPtr<IPooledRenderTarget>& VelocityRT)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
static const auto AllowStaticLightingVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AllowStaticLighting"));
const bool bUseLightmaps = (AllowStaticLightingVar->GetValueOnRenderThread() == 1);
TRefCountPtr<IPooledRenderTarget> NewSceneColor;
{
ResolveSceneColor(RHICmdList);
FPooledRenderTargetDesc Desc = SceneContext.GetSceneColor()->GetDesc();
Desc.TargetableFlags |= TexCreate_UAV;
Desc.TargetableFlags |= TexCreate_NoFastClear;
Desc.ClearValue = FClearValueBinding::None;
// we don't create a new name to make it easier to use "vis SceneColor" and get the last HDRSceneColor
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, NewSceneColor, TEXT("SceneColor") );
}
// If we are in SM5, use the compute shader gather method
for (int32 ViewIndex = 0, Num = Views.Num(); ViewIndex < Num; ViewIndex++)
{
FViewInfo& View = Views[ViewIndex];
const uint32 bSSR = ShouldRenderScreenSpaceReflections(Views[ViewIndex]);
TRefCountPtr<IPooledRenderTarget> SSROutput = GSystemTextures.BlackDummy;
if( bSSR )
{
RenderScreenSpaceReflections(RHICmdList, View, SSROutput, VelocityRT);
}
SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ReflectionEnvironment)
RenderDeferredPlanarReflections(RHICmdList, View, false, SSROutput);
// ReflectionEnv is assumed to be on when going into this method
{
SetRenderTarget(RHICmdList, NULL, NULL);
FReflectionEnvironmentTiledDeferredCS* ComputeShader = NULL;
// Render the reflection environment with tiled deferred culling
bool bHasBoxCaptures = (View.NumBoxReflectionCaptures > 0);
bool bHasSphereCaptures = (View.NumSphereReflectionCaptures > 0);
bool bHasSkyLight = Scene && Scene->SkyLight && !Scene->SkyLight->bHasStaticLighting;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Note: FReflectionEnvironmentTiledDeferredCS is async compute just to test the async compute API.
// It doesn't actually overlap with anything and therefore can't achieve any gains.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static const FName TiledReflBeginComputeName(TEXT("ReflectionEnvBeginComputeFence"));
static const FName TiledReflEndComputeName(TEXT("ReflectionEnvEndComputeFence"));
FComputeFenceRHIRef ReflectionBeginFence = RHICmdList.CreateComputeFence(TiledReflBeginComputeName);
FComputeFenceRHIRef ReflectionEndFence = RHICmdList.CreateComputeFence(TiledReflEndComputeName);
//Grab the async compute commandlist.
FRHIAsyncComputeCommandListImmediate& RHICmdListComputeImmediate = FRHICommandListExecutor::GetImmediateAsyncComputeCommandList();
{
SCOPED_COMPUTE_EVENTF(RHICmdListComputeImmediate, ReflectionEnvironment, TEXT("ReflectionEnvironment ComputeShader %dx%d Tile:%dx%d Box:%d Sphere:%d SkyLight:%d"),
View.ViewRect.Width(), View.ViewRect.Height(), GReflectionEnvironmentTileSizeX, GReflectionEnvironmentTileSizeY,
View.NumBoxReflectionCaptures, View.NumSphereReflectionCaptures, bHasSkyLight);
ComputeShader = SelectReflectionEnvironmentTiledDeferredCS(View.ShaderMap, bUseLightmaps, bHasSkyLight, bHasBoxCaptures, bHasSphereCaptures, DynamicBentNormalAO != NULL);
//Really we should write this fence where we transition the final depedency for the reflections. We may add an RHI command just for writing fences if this
//can't be done in the general case. In the meantime, hack this command a bit to write the fence.
RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EGfxToCompute, nullptr, 0, ReflectionBeginFence);
//we must wait on the fence written from the Gfx pipe to let us know all our dependencies are ready.
RHICmdListComputeImmediate.WaitComputeFence(ReflectionBeginFence);
//standard compute setup, but on the async commandlist.
RHICmdListComputeImmediate.SetComputeShader(ComputeShader->GetComputeShader());
FUnorderedAccessViewRHIParamRef OutUAV = NewSceneColor->GetRenderTargetItem().UAV;
ComputeShader->SetParameters(RHICmdListComputeImmediate, View, SSROutput->GetRenderTargetItem().ShaderResourceTexture, OutUAV, DynamicBentNormalAO);
uint32 GroupSizeX = (View.ViewRect.Size().X + GReflectionEnvironmentTileSizeX - 1) / GReflectionEnvironmentTileSizeX;
uint32 GroupSizeY = (View.ViewRect.Size().Y + GReflectionEnvironmentTileSizeY - 1) / GReflectionEnvironmentTileSizeY;
DispatchComputeShader(RHICmdListComputeImmediate, ComputeShader, GroupSizeX, GroupSizeY, 1);
ComputeShader->UnsetParameters(RHICmdListComputeImmediate, OutUAV);
//transition the output to readable and write the fence to allow the Gfx pipe to carry on.
RHICmdListComputeImmediate.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToGfx, &OutUAV, 1, ReflectionEndFence);
}
//immediately dispatch our async compute commands to the RHI thread to be submitted to the GPU as soon as possible.
//dispatch after the scope so the drawevent pop is inside the dispatch
FRHIAsyncComputeCommandListImmediate::ImmediateDispatch(RHICmdListComputeImmediate);
//Gfx pipe must wait for the async compute reflection job to complete.
RHICmdList.WaitComputeFence(ReflectionEndFence);
}
}
SceneContext.SetSceneColor(NewSceneColor);
check(SceneContext.GetSceneColor());
}
void FDeferredShadingSceneRenderer::RenderStandardDeferredImageBasedReflections(FRHICommandListImmediate& RHICmdList, FGraphicsPipelineStateInitializer& GraphicsPSOInit, bool bReflectionEnv, const TRefCountPtr<IPooledRenderTarget>& DynamicBentNormalAO, TRefCountPtr<IPooledRenderTarget>& VelocityRT)
{
if(!ViewFamily.EngineShowFlags.Lighting)
{
return;
}
const bool bSkyLight = Scene->SkyLight
&& Scene->SkyLight->ProcessedTexture
&& !Scene->SkyLight->bHasStaticLighting
&& ViewFamily.EngineShowFlags.SkyLighting;
static TArray<FReflectionCaptureSortData> SortData;
if (bReflectionEnv)
{
// shared for multiple views
SortData.Reset(Scene->ReflectionSceneData.RegisteredReflectionCaptures.Num());
// Gather visible reflection capture data
for (int32 ReflectionProxyIndex = 0; ReflectionProxyIndex < Scene->ReflectionSceneData.RegisteredReflectionCaptures.Num() && SortData.Num() < GMaxNumReflectionCaptures; ReflectionProxyIndex++)
{
FReflectionCaptureProxy* CurrentCapture = Scene->ReflectionSceneData.RegisteredReflectionCaptures[ReflectionProxyIndex];
FReflectionCaptureSortData NewSortEntry;
NewSortEntry.CaptureIndex = -1;
if (FeatureLevel >= ERHIFeatureLevel::SM5)
{
const FCaptureComponentSceneState* ComponentStatePtr = Scene->ReflectionSceneData.AllocatedReflectionCaptureState.Find(CurrentCapture->Component);
NewSortEntry.CaptureIndex = ComponentStatePtr ? ComponentStatePtr->CaptureIndex : -1;
}
NewSortEntry.SM4FullHDRCubemap = CurrentCapture->SM4FullHDRCubemap;
NewSortEntry.Guid = CurrentCapture->Guid;
NewSortEntry.PositionAndRadius = FVector4(CurrentCapture->Position, CurrentCapture->InfluenceRadius);
float ShapeTypeValue = (float)CurrentCapture->Shape;
NewSortEntry.CaptureProperties = FVector4(CurrentCapture->Brightness, 0, ShapeTypeValue, 0);
NewSortEntry.CaptureOffsetAndAverageBrightness = FVector4(CurrentCapture->CaptureOffset, CurrentCapture->AverageBrightness);
if (CurrentCapture->Shape == EReflectionCaptureShape::Plane)
{
NewSortEntry.BoxTransform = FMatrix(
FPlane(CurrentCapture->ReflectionPlane),
FPlane(CurrentCapture->ReflectionXAxisAndYScale),
FPlane(0, 0, 0, 0),
FPlane(0, 0, 0, 0));
NewSortEntry.BoxScales = FVector4(0);
}
else
{
NewSortEntry.BoxTransform = CurrentCapture->BoxTransform;
NewSortEntry.BoxScales = FVector4(CurrentCapture->BoxScales, CurrentCapture->BoxTransitionDistance);
}
SortData.Add(NewSortEntry);
}
SortData.Sort();
}
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
// Use standard deferred shading to composite reflection capture contribution
for (int32 ViewIndex = 0, Num = Views.Num(); ViewIndex < Num; ViewIndex++)
{
FViewInfo& View = Views[ViewIndex];
FSceneViewState* ViewState = (FSceneViewState*)View.State;
bool bLPV = false;
if(ViewState && ViewState->GetLightPropagationVolume(View.GetFeatureLevel()))
{
const FLightPropagationVolumeSettings& LPVSettings = View.FinalPostProcessSettings.BlendableManager.GetSingleFinalDataConst<FLightPropagationVolumeSettings>();
bLPV = LPVSettings.LPVIntensity > 0.0f;
}
bool bAmbient = View.FinalPostProcessSettings.ContributingCubemaps.Num() > 0;
bool bMixing = bLPV && (CVarLPVMixing.GetValueOnRenderThread() != 0);
bool bEnvironmentMixing = bMixing && (bAmbient || bLPV);
bool bRequiresApply = bSkyLight
// If Reflection Environment is active and mixed with indirect lighting (Ambient + LPV), apply is required!
|| (View.Family->EngineShowFlags.ReflectionEnvironment && (bReflectionEnv || bEnvironmentMixing) );
const bool bSSR = ShouldRenderScreenSpaceReflections(View);
TRefCountPtr<IPooledRenderTarget> SSROutput = GSystemTextures.BlackDummy;
if (bSSR)
{
bRequiresApply = true;
RenderScreenSpaceReflections(RHICmdList, View, SSROutput, VelocityRT);
}
SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ReflectionEnvironment)
bool bApplyFromSSRTexture = bSSR;
if (RenderDeferredPlanarReflections(RHICmdList, View, true, SSROutput))
{
bRequiresApply = true;
bApplyFromSSRTexture = true;
}
/* Light Accumulation moved to SceneRenderTargets */
TRefCountPtr<IPooledRenderTarget> LightAccumulation = SceneContext.LightAccumulation;
if (!LightAccumulation)
{
// should never be used but during debugging it can happen
ensureMsgf(LightAccumulation, TEXT("White dummy system texture about to be corrupted."));
LightAccumulation = GSystemTextures.WhiteDummy;
}
if (bReflectionEnv)
{
bRequiresApply = true;
SCOPED_DRAW_EVENTF(RHICmdList, ReflectionEnvironment, TEXT("ReflectionEnvironment PixelShader"));
{
// Clear to no reflection contribution, alpha of 1 indicates full background contribution
ESimpleRenderTargetMode SimpleRenderTargetMode = ESimpleRenderTargetMode::EExistingColorAndDepth;
// If Reflection Environment is mixed with indirect lighting (Ambient + LPV), skip clear!
if (!bMixing)
{
SimpleRenderTargetMode = ESimpleRenderTargetMode::EClearColorExistingDepth;
}
SetRenderTarget(RHICmdList, LightAccumulation->GetRenderTargetItem().TargetableTexture, NULL, SimpleRenderTargetMode);
}
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
// rgb accumulates reflection contribution front to back, alpha accumulates (1 - alpha0) * (1 - alpha 1)...
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_DestAlpha, BF_One, BO_Add, BF_Zero, BF_InverseSourceAlpha>::GetRHI();
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
for (int32 ReflectionCaptureIndex = 0; ReflectionCaptureIndex < SortData.Num(); ReflectionCaptureIndex++)
{
const FReflectionCaptureSortData& ReflectionCapture = SortData[ReflectionCaptureIndex];
if (FeatureLevel >= ERHIFeatureLevel::SM5 || ReflectionCapture.SM4FullHDRCubemap)
{
const FSphere LightBounds(ReflectionCapture.PositionAndRadius, ReflectionCapture.PositionAndRadius.W);
TShaderMapRef<TDeferredLightVS<true> > VertexShader(View.ShaderMap);
SetBoundingGeometryRasterizerAndDepthState(GraphicsPSOInit, View, LightBounds);
// Use the appropriate shader for the capture shape
if (ReflectionCapture.CaptureProperties.Z == 0)
{
TShaderMapRef<TStandardDeferredReflectionPS<true> > PixelShader(View.ShaderMap);
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4();
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader);
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader);
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
PixelShader->SetParameters(RHICmdList, View, ReflectionCapture);
}
else
{
TShaderMapRef<TStandardDeferredReflectionPS<false> > PixelShader(View.ShaderMap);
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4();
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader);
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader);
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
PixelShader->SetParameters(RHICmdList, View, ReflectionCapture);
}
VertexShader->SetSimpleLightParameters(RHICmdList, View, LightBounds);
StencilingGeometry::DrawSphere(RHICmdList);
}
}
RHICmdList.CopyToResolveTarget(LightAccumulation->GetRenderTargetItem().TargetableTexture, LightAccumulation->GetRenderTargetItem().ShaderResourceTexture, false, FResolveParams());
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, LightAccumulation);
}
if (bRequiresApply)
{
// Apply reflections to screen
SCOPED_DRAW_EVENT(RHICmdList, ReflectionApply);
SCOPED_GPU_STAT(RHICmdList, Stat_GPU_ReflectionEnvironment);
SceneContext.BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EUninitializedColorExistingDepth, FExclusiveDepthStencil::DepthRead_StencilWrite, true);
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
if (GetReflectionEnvironmentCVar() == 2)
{
// override scene color for debugging
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
}
else
{
// additive to scene color
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One>::GetRHI();
}
TShaderMapRef< FPostProcessVS > VertexShader(View.ShaderMap);
// Activate Reflection Environment if we choose to mix it with indirect lighting (Ambient + LPV)
// todo: refactor (we abuse another boolean to pass the data through)
bReflectionEnv = bReflectionEnv || bEnvironmentMixing;
const bool bSupportDFAOIndirectShadowing = DynamicBentNormalAO != NULL;
#define CASE(A,B,C,D) \
case ((A << 3) | (B << 2) | (C << 1) | D) : \
{ \
TShaderMapRef< FReflectionApplyPS<A, B, C, D> > PixelShader(View.ShaderMap); \
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI; \
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader); \
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader); \
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit); \
PixelShader->SetParameters(RHICmdList, View, LightAccumulation->GetRenderTargetItem().ShaderResourceTexture, SSROutput->GetRenderTargetItem().ShaderResourceTexture, DynamicBentNormalAO); \
}; \
break
switch (((uint32)bApplyFromSSRTexture << 3) | ((uint32)bReflectionEnv << 2) | ((uint32)bSkyLight << 1) | (uint32)bSupportDFAOIndirectShadowing)
{
CASE(0, 0, 0, 0);
CASE(0, 0, 1, 0);
CASE(0, 1, 0, 0);
CASE(0, 1, 1, 0);
CASE(1, 0, 0, 0);
CASE(1, 0, 1, 0);
CASE(1, 1, 0, 0);
CASE(1, 1, 1, 0);
CASE(0, 0, 0, 1);
CASE(0, 0, 1, 1);
CASE(0, 1, 0, 1);
CASE(0, 1, 1, 1);
CASE(1, 0, 0, 1);
CASE(1, 0, 1, 1);
CASE(1, 1, 0, 1);
CASE(1, 1, 1, 1);
}
#undef CASE
DrawRectangle(
RHICmdList,
0, 0,
View.ViewRect.Width(), View.ViewRect.Height(),
View.ViewRect.Min.X, View.ViewRect.Min.Y,
View.ViewRect.Width(), View.ViewRect.Height(),
FIntPoint(View.ViewRect.Width(), View.ViewRect.Height()),
SceneContext.GetBufferSizeXY(),
*VertexShader);
ResolveSceneColor(RHICmdList);
}
}
}
void FDeferredShadingSceneRenderer::RenderDeferredReflections(FRHICommandListImmediate& RHICmdList, const TRefCountPtr<IPooledRenderTarget>& DynamicBentNormalAO, TRefCountPtr<IPooledRenderTarget>& VelocityRT)
{
if (ViewFamily.EngineShowFlags.VisualizeLightCulling)
{
return;
}
bool bAnyViewIsReflectionCapture = false;
for (int32 ViewIndex = 0, Num = Views.Num(); ViewIndex < Num; ViewIndex++)
{
const FViewInfo& View = Views[ViewIndex];
bAnyViewIsReflectionCapture = bAnyViewIsReflectionCapture || View.bIsReflectionCapture;
}
FGraphicsPipelineStateInitializer GraphicsPSOInit;
// If we're currently capturing a reflection capture, output SpecularColor * IndirectIrradiance for metals so they are not black in reflections,
// Since we don't have multiple bounce specular reflections
if (bAnyViewIsReflectionCapture)
{
RenderReflectionCaptureSpecularBounceForAllViews(RHICmdList, GraphicsPSOInit);
}
else
{
const uint32 bDoTiledReflections = CVarDoTiledReflections.GetValueOnRenderThread() != 0;
const bool bReflectionEnvironment = ShouldDoReflectionEnvironment();
const bool bReflectionsWithCompute = bDoTiledReflections && RHISupportsComputeShaders(ViewFamily.GetShaderPlatform()) && bReflectionEnvironment && Scene->ReflectionSceneData.CubemapArray.IsValid();
if (bReflectionsWithCompute)
{
RenderTiledDeferredImageBasedReflections(RHICmdList, DynamicBentNormalAO, VelocityRT);
}
else
{
RenderStandardDeferredImageBasedReflections(RHICmdList, GraphicsPSOInit, bReflectionEnvironment, DynamicBentNormalAO, VelocityRT);
}
}
}