// Copyright 1998-2015 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 "RendererPrivate.h" #include "ScenePrivate.h" #include "SceneFilterRendering.h" #include "PostProcessing.h" #include "UniformBuffer.h" #include "ShaderParameters.h" #include "ScreenRendering.h" #include "ScreenSpaceReflections.h" #include "PostProcessTemporalAA.h" #include "PostProcessDownsample.h" #include "ReflectionEnvironment.h" #include "ShaderParameterUtils.h" #include "LightRendering.h" #include "SceneUtils.h" /** Tile size for the reflection environment compute shader, tweaked for 680 GTX. */ const int32 GReflectionEnvironmentTileSizeX = 16; const int32 GReflectionEnvironmentTileSizeY = 16; extern ENGINE_API int32 GReflectionCaptureSize; static TAutoConsoleVariable CVarDiffuseFromCaptures( TEXT("r.DiffuseFromCaptures"), 0, TEXT("Apply indirect diffuse lighting from captures instead of lightmaps.\n") TEXT(" 0 is off (default), 1 is on"), ECVF_RenderThreadSafe); #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) static TAutoConsoleVariable CVarReflectionEnvironment( TEXT("r.ReflectionEnvironment"), 1, TEXT("0:off, 1:on and blend with scene, 2:on and overwrite scene.\n") TEXT("Whether to render the reflection environment feature, which implements local reflections through Reflection Capture actors."), ECVF_Cheat | ECVF_RenderThreadSafe); #endif static TAutoConsoleVariable CVarHalfResReflections( TEXT("r.HalfResReflections"), 0, TEXT("Compute ReflectionEnvironment samples at half resolution.\n") TEXT(" 0 is off (default), 1 is on"), ECVF_RenderThreadSafe); static TAutoConsoleVariable CVarDoTiledReflections( TEXT("r.DoTiledReflections"), 1, TEXT("Compute Reflection Environment with Tiled compute shader..\n") TEXT(" 1 is on (default), 1 is on"), ECVF_RenderThreadSafe); static TAutoConsoleVariable CVarSkySpecularOcclusionStrength( TEXT("r.SkySpecularOcclusionStrength"), 1, TEXT("Strength of skylight specular occlusion from DFAO"), ECVF_RenderThreadSafe); // to avoid having direct access from many places static int GetReflectionEnvironmentCVar() { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) return CVarReflectionEnvironment.GetValueOnAnyThread(); #endif // on, default mode return 1; } bool IsReflectionEnvironmentAvailable(ERHIFeatureLevel::Type InFeatureLevel) { static const auto AllowStaticLightingVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AllowStaticLighting")); const bool bAllowStaticLighting = (!AllowStaticLightingVar || AllowStaticLightingVar->GetValueOnAnyThread() != 0); return (InFeatureLevel >= ERHIFeatureLevel::SM4) && (GetReflectionEnvironmentCVar() != 0) && bAllowStaticLighting; } void FReflectionEnvironmentCubemapArray::InitDynamicRHI() { if (GetFeatureLevel() >= ERHIFeatureLevel::SM5) { const int32 NumReflectionCaptureMips = FMath::CeilLogTwo(GReflectionCaptureSize) + 1; ReleaseCubeArray(); FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::CreateCubemapDesc( GReflectionCaptureSize, //@todo - get rid of the alpha channel (currently stores brightness which is a constant), could use PF_FloatRGB for half memory, would need to implement RHIReadSurface support PF_FloatRGBA, TexCreate_None, TexCreate_None, false, // Cubemap array of 1 produces a regular cubemap, so guarantee it will be allocated as an array FMath::Max(MaxCubemaps, 2), NumReflectionCaptureMips)); // Allocate TextureCubeArray for the scene's reflection captures GRenderTargetPool.FindFreeElement(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 FReflectionEnvironmentCubemapArray::UpdateMaxCubemaps(uint32 InMaxCubemaps) { MaxCubemaps = InMaxCubemaps; // 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")); MinSkySpecularOcclusion.Bind(ParameterMap, TEXT("MinSkySpecularOcclusion")); } template void SetParameters(FRHICommandList& RHICmdList, const ShaderRHIParamRef& ShaderRHI, const TRefCountPtr& DynamicBentNormalAO, float SkySpecularOcclusionStrength, float MinOcclusionValue) { FTextureRHIParamRef BentNormalAO = GWhiteTexture->TextureRHI; bool bApplyBentNormalAO = false; if (DynamicBentNormalAO) { BentNormalAO = DynamicBentNormalAO->GetRenderTargetItem().ShaderResourceTexture; bApplyBentNormalAO = true; } SetTextureParameter(RHICmdList, ShaderRHI, BentNormalAOTexture, BentNormalAOSampler, TStaticSamplerState::GetRHI(), BentNormalAO); SetShaderValue(RHICmdList, ShaderRHI, ApplyBentNormalAO, bApplyBentNormalAO ? 1.0f : 0.0f); SetShaderValue(RHICmdList, ShaderRHI, InvSkySpecularOcclusionStrength, 1.0f / FMath::Max(SkySpecularOcclusionStrength, .1f)); SetShaderValue(RHICmdList, ShaderRHI, MinSkySpecularOcclusion, MinOcclusionValue); } friend FArchive& operator<<(FArchive& Ar,FDistanceFieldAOSpecularOcclusionParameters& P) { Ar << P.BentNormalAOTexture << P.BentNormalAOSampler << P.ApplyBentNormalAO << P.InvSkySpecularOcclusionStrength << P.MinSkySpecularOcclusion; return Ar; } private: FShaderResourceParameter BentNormalAOTexture; FShaderResourceParameter BentNormalAOSampler; FShaderParameter ApplyBentNormalAO; FShaderParameter InvSkySpecularOcclusionStrength; FShaderParameter MinSkySpecularOcclusion; }; struct FReflectionCaptureSortData { uint32 Guid; int32 CaptureIndex; FVector4 PositionAndRadius; FVector4 CaptureProperties; FMatrix BoxTransform; FVector4 BoxScales; 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; } } }; /** Per-reflection capture data needed by the shader. */ BEGIN_UNIFORM_BUFFER_STRUCT(FReflectionCaptureData,) DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER_ARRAY(FVector4,PositionAndRadius,[GMaxNumReflectionCaptures]) // R is brightness, G is array index, B is shape DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER_ARRAY(FVector4,CaptureProperties,[GMaxNumReflectionCaptures]) // Stores the box transform for a box shape, other data is packed for other shapes DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER_ARRAY(FMatrix,BoxTransform,[GMaxNumReflectionCaptures]) DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER_ARRAY(FVector4,BoxScales,[GMaxNumReflectionCaptures]) END_UNIFORM_BUFFER_STRUCT(FReflectionCaptureData) 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.SetDefine(TEXT("TILED_DEFERRED_CULL_SHADER"), 1); OutEnvironment.CompilerFlags.Add(CFLAG_StandardOptimization); } FReflectionEnvironmentTiledDeferredCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FGlobalShader(Initializer) { DeferredParameters.Bind(Initializer.ParameterMap); ReflectionEnvironmentColorTexture.Bind(Initializer.ParameterMap,TEXT("ReflectionEnvironmentColorTexture")); ReflectionEnvironmentColorSampler.Bind(Initializer.ParameterMap,TEXT("ReflectionEnvironmentColorSampler")); 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); } FReflectionEnvironmentTiledDeferredCS() { } void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, FTextureRHIParamRef SSRTexture, TArray& SortData, FUnorderedAccessViewRHIParamRef OutSceneColorUAV, const TRefCountPtr& DynamicBentNormalAO) { const FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View); 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, ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, TStaticSamplerState::GetRHI(), CubemapArray.ShaderResourceTexture); SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceReflections, SSRTexture ); SetTextureParameter(RHICmdList, ShaderRHI, InSceneColor, GSceneRenderTargets.GetSceneColor()->GetRenderTargetItem().ShaderResourceTexture ); OutSceneColor.SetTexture(RHICmdList, ShaderRHI, NULL, OutSceneColorUAV); SetShaderValue(RHICmdList, ShaderRHI, ViewDimensionsParameter, View.ViewRect); FReflectionCaptureData SamplePositionsBuffer; for (int32 CaptureIndex = 0; CaptureIndex < SortData.Num(); CaptureIndex++) { SamplePositionsBuffer.PositionAndRadius[CaptureIndex] = SortData[CaptureIndex].PositionAndRadius; SamplePositionsBuffer.CaptureProperties[CaptureIndex] = SortData[CaptureIndex].CaptureProperties; SamplePositionsBuffer.BoxTransform[CaptureIndex] = SortData[CaptureIndex].BoxTransform; SamplePositionsBuffer.BoxScales[CaptureIndex] = SortData[CaptureIndex].BoxScales; } SetUniformBufferParameterImmediate(RHICmdList, ShaderRHI, GetUniformBufferParameter(), SamplePositionsBuffer); SetShaderValue(RHICmdList, ShaderRHI, NumCaptures, SortData.Num()); SetTextureParameter(RHICmdList, ShaderRHI, PreIntegratedGF, PreIntegratedGFSampler, TStaticSamplerState::GetRHI(), GSystemTextures.PreintegratedGF->GetRenderTargetItem().ShaderResourceTexture); SkyLightParameters.SetParameters(RHICmdList, ShaderRHI, Scene, View.Family->EngineShowFlags.SkyLighting); const float MinOcclusion = Scene->SkyLight ? Scene->SkyLight->MinOcclusion : 0; SpecularOcclusionParameters.SetParameters(RHICmdList, ShaderRHI, DynamicBentNormalAO, CVarSkySpecularOcclusionStrength.GetValueOnRenderThread(), MinOcclusion); } void UnsetParameters(FRHICommandList& RHICmdList) { const FComputeShaderRHIParamRef ShaderRHI = GetComputeShader(); OutSceneColor.UnsetUAV(RHICmdList, ShaderRHI); } virtual bool Serialize(FArchive& Ar) override { bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); Ar << DeferredParameters; Ar << ReflectionEnvironmentColorTexture; Ar << ReflectionEnvironmentColorSampler; Ar << ScreenSpaceReflections; Ar << InSceneColor; Ar << OutSceneColor; Ar << NumCaptures; Ar << ViewDimensionsParameter; Ar << PreIntegratedGF; Ar << PreIntegratedGFSampler; Ar << SkyLightParameters; Ar << SpecularOcclusionParameters; return bShaderHasOutdatedParameters; } private: FDeferredPixelShaderParameters DeferredParameters; FShaderResourceParameter ReflectionEnvironmentColorTexture; FShaderResourceParameter ReflectionEnvironmentColorSampler; FShaderResourceParameter ScreenSpaceReflections; FShaderResourceParameter InSceneColor; FRWShaderParameter OutSceneColor; FShaderParameter NumCaptures; FShaderParameter ViewDimensionsParameter; FShaderResourceParameter PreIntegratedGF; FShaderResourceParameter PreIntegratedGFSampler; FSkyLightReflectionParameters SkyLightParameters; FDistanceFieldAOSpecularOcclusionParameters SpecularOcclusionParameters; }; template< uint32 bUseLightmaps, uint32 bUseClearCoat, uint32 bBoxCapturesOnly, uint32 bSphereCapturesOnly > 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("USE_CLEARCOAT"), bUseClearCoat); OutEnvironment.SetDefine(TEXT("HAS_BOX_CAPTURES"), bBoxCapturesOnly); OutEnvironment.SetDefine(TEXT("HAS_SPHERE_CAPTURES"), bSphereCapturesOnly); } }; // 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) \ typedef TReflectionEnvironmentTiledDeferredCS TReflectionEnvironmentTiledDeferredCS##A##B##C##D; \ IMPLEMENT_SHADER_TYPE(template<>,TReflectionEnvironmentTiledDeferredCS##A##B##C##D,TEXT("ReflectionEnvironmentComputeShaders"),TEXT("ReflectionEnvironmentTiledDeferredMain"),SF_Compute) IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 0, 0, 0); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 0, 0, 1); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 0, 1, 0); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 0, 1, 1); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 1, 0, 0); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 1, 0, 1); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 1, 1, 0); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(0, 1, 1, 1); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 0, 0, 0); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 0, 0, 1); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 0, 1, 0); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 0, 1, 1); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 1, 0, 0); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 1, 0, 1); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 1, 1, 0); IMPLEMENT_REFLECTION_COMPUTESHADER_TYPE(1, 1, 1, 1); template< uint32 bSSR, uint32 bReflectionEnv, uint32 bSkylight > 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); } /** 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& DynamicBentNormalAO) { const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View); DeferredParameters.Set(RHICmdList, ShaderRHI, View); SkyLightParameters.SetParameters(RHICmdList, ShaderRHI, (FScene*)View.Family->Scene, true); SetTextureParameter(RHICmdList, ShaderRHI, ReflectionEnvTexture, ReflectionEnvSampler, TStaticSamplerState::GetRHI(), ReflectionEnv ); SetTextureParameter(RHICmdList, ShaderRHI, ScreenSpaceReflectionsTexture, ScreenSpaceReflectionsSampler, TStaticSamplerState::GetRHI(), ScreenSpaceReflections ); SetTextureParameter(RHICmdList, ShaderRHI, PreIntegratedGF, PreIntegratedGFSampler, TStaticSamplerState::GetRHI(), GSystemTextures.PreintegratedGF->GetRenderTargetItem().ShaderResourceTexture ); FScene* Scene = (FScene*)View.Family->Scene; const float MinOcclusion = Scene->SkyLight ? Scene->SkyLight->MinOcclusion : 0; SpecularOcclusionParameters.SetParameters(RHICmdList, ShaderRHI, DynamicBentNormalAO, CVarSkySpecularOcclusionStrength.GetValueOnRenderThread(), 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) \ typedef FReflectionApplyPS FReflectionApplyPS##A##B##C; \ IMPLEMENT_SHADER_TYPE(template<>,FReflectionApplyPS##A##B##C,TEXT("ReflectionEnvironmentShaders"),TEXT("ReflectionApplyPS"),SF_Pixel); IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(0,0,0); IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(0,0,1); IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(0,1,0); IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(0,1,1); IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(1,0,0); IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(1,0,1); IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(1,1,0); IMPLEMENT_REFLECTION_APPLY_PIXELSHADER_TYPE(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(RHICmdList, ShaderRHI, View); 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 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")); 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(RHICmdList, ShaderRHI, View); 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::GetRHI(), CubemapArray.ShaderResourceTexture); SetShaderValue(RHICmdList, ShaderRHI, CaptureArrayIndex, SortData.CaptureIndex); } else { SetTextureParameter(RHICmdList, ShaderRHI, ReflectionEnvironmentColorTexture, ReflectionEnvironmentColorSampler, TStaticSamplerState::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); } // FShader interface. virtual bool Serialize(FArchive& Ar) override { bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); Ar << CapturePositionAndRadius; Ar << CaptureProperties; Ar << CaptureBoxTransform; Ar << CaptureBoxScales; Ar << CaptureArrayIndex; Ar << ReflectionEnvironmentColorTexture; Ar << ReflectionEnvironmentColorTextureArray; Ar << ReflectionEnvironmentColorSampler; Ar << DeferredParameters; return bShaderHasOutdatedParameters; } private: FShaderParameter CapturePositionAndRadius; FShaderParameter CaptureProperties; FShaderParameter CaptureBoxTransform; FShaderParameter CaptureBoxScales; FShaderParameter CaptureArrayIndex; FShaderResourceParameter ReflectionEnvironmentColorTexture; FShaderResourceParameter ReflectionEnvironmentColorTextureArray; FShaderResourceParameter ReflectionEnvironmentColorSampler; FDeferredPixelShaderParameters DeferredParameters; }; IMPLEMENT_SHADER_TYPE(template<>,TStandardDeferredReflectionPS,TEXT("ReflectionEnvironmentShaders"),TEXT("StandardDeferredReflectionPS"),SF_Pixel); IMPLEMENT_SHADER_TYPE(template<>,TStandardDeferredReflectionPS,TEXT("ReflectionEnvironmentShaders"),TEXT("StandardDeferredReflectionPS"),SF_Pixel); void FDeferredShadingSceneRenderer::RenderReflectionCaptureSpecularBounceForAllViews(FRHICommandListImmediate& RHICmdList) { GSceneRenderTargets.BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EUninitializedColorExistingDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); RHICmdList.SetRasterizerState(TStaticRasterizerState< FM_Solid, CM_None >::GetRHI()); RHICmdList.SetDepthStencilState(TStaticDepthStencilState< false, CF_Always >::GetRHI()); RHICmdList.SetBlendState(TStaticBlendState< CW_RGB, BO_Add, BF_One, BF_One >::GetRHI()); auto ShaderMap = GetGlobalShaderMap(FeatureLevel); TShaderMapRef< FPostProcessVS > VertexShader(ShaderMap); TShaderMapRef< FReflectionCaptureSpecularBouncePS > PixelShader(ShaderMap); static FGlobalBoundShaderState BoundShaderState; SetGlobalBoundShaderState(RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); 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()), GSceneRenderTargets.GetBufferSizeXY(), *VertexShader, EDRF_UseTriangleOptimization); } GSceneRenderTargets.FinishRenderingSceneColor(RHICmdList); } bool FDeferredShadingSceneRenderer::ShouldDoReflectionEnvironment() const { const ERHIFeatureLevel::Type FeatureLevel = Scene->GetFeatureLevel(); return IsReflectionEnvironmentAvailable(FeatureLevel) && Scene->ReflectionSceneData.RegisteredReflectionCaptures.Num() && ViewFamily.EngineShowFlags.ReflectionEnvironment && (FeatureLevel == ERHIFeatureLevel::SM4 || Scene->ReflectionSceneData.CubemapArray.IsValid()); } void GatherAndSortReflectionCaptures(const FScene* Scene, TArray& OutSortData, int32& OutNumBoxCaptures, int32& OutNumSphereCaptures) { OutSortData.Reset(Scene->ReflectionSceneData.RegisteredReflectionCaptures.Num()); OutNumBoxCaptures = 0; OutNumSphereCaptures = 0; const int32 MaxCubemaps = Scene->ReflectionSceneData.CubemapArray.GetMaxCubemaps(); // Pack only visible reflection captures into the uniform buffer, each with an index to its cubemap array entry 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); 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); } OutSortData.Add(NewSortEntry); } } OutSortData.Sort(); } FReflectionEnvironmentTiledDeferredCS* SelectReflectionEnvironmentTiledDeferredCS(TShaderMap* ShaderMap, bool bUseLightmaps, bool bUseClearCoat, bool bHasBoxCaptures, bool bHasSphereCaptures) { FReflectionEnvironmentTiledDeferredCS* ComputeShader = nullptr; if (bUseLightmaps) { if (bUseClearCoat) { if (bHasBoxCaptures && bHasSphereCaptures) { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 1, 1, 1> >(ShaderMap); } else if (bHasBoxCaptures) { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 1, 1, 0> >(ShaderMap); } else if (bHasSphereCaptures) { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 1, 0, 1> >(ShaderMap); } else { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 1, 0, 0> >(ShaderMap); } } else { if (bHasBoxCaptures && bHasSphereCaptures) { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 0, 1, 1> >(ShaderMap); } else if (bHasBoxCaptures) { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 0, 1, 0> >(ShaderMap); } else if (bHasSphereCaptures) { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 0, 0, 1> >(ShaderMap); } else { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<1, 0, 0, 0> >(ShaderMap); } } } else { if (bUseClearCoat) { if (bHasBoxCaptures && bHasSphereCaptures) { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 1, 1, 1> >(ShaderMap); } else if (bHasBoxCaptures) { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 1, 1, 0> >(ShaderMap); } else if (bHasSphereCaptures) { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 1, 0, 1> >(ShaderMap); } else { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 1, 0, 0> >(ShaderMap); } } else { if (bHasBoxCaptures && bHasSphereCaptures) { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 0, 1, 1> >(ShaderMap); } else if (bHasBoxCaptures) { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 0, 1, 0> >(ShaderMap); } else if (bHasSphereCaptures) { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 0, 0, 1> >(ShaderMap); } else { ComputeShader = *TShaderMapRef< TReflectionEnvironmentTiledDeferredCS<0, 0, 0, 0> >(ShaderMap); } } } check(ComputeShader); return ComputeShader; } void FDeferredShadingSceneRenderer::RenderTiledDeferredImageBasedReflections(FRHICommandListImmediate& RHICmdList, const TRefCountPtr& DynamicBentNormalAO) { const bool bUseLightmaps = CVarDiffuseFromCaptures.GetValueOnRenderThread() == 0; const uint32 bHalfRes = CVarHalfResReflections.GetValueOnRenderThread() != 0; TRefCountPtr NewSceneColor; { GSceneRenderTargets.ResolveSceneColor(RHICmdList, FResolveRect(0, 0, ViewFamily.FamilySizeX, ViewFamily.FamilySizeY)); FPooledRenderTargetDesc Desc = GSceneRenderTargets.GetSceneColor()->GetDesc(); Desc.TargetableFlags |= TexCreate_UAV; // we don't create a new name to make it easier to use "vis SceneColor" and get the last HDRSceneColor GRenderTargetPool.FindFreeElement( 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 = DoScreenSpaceReflections(Views[ViewIndex]); TRefCountPtr SSROutput = GSystemTextures.BlackDummy; if( bSSR ) { ScreenSpaceReflections(RHICmdList, View, SSROutput); } // ReflectionEnv is assumed to be on when going into this method { // Render the reflection environment with tiled deferred culling SCOPED_DRAW_EVENT(RHICmdList, ReflectionEnvironmentGather); SetRenderTarget(RHICmdList, NULL, NULL); FReflectionEnvironmentTiledDeferredCS* ComputeShader = NULL; uint32 AdjustedReflectionTileSizeX = GReflectionEnvironmentTileSizeX; if (bHalfRes) { AdjustedReflectionTileSizeX *= 2; } TArray SortData; int32 NumBoxCaptures = 0; int32 NumSphereCaptures = 0; GatherAndSortReflectionCaptures(Scene, SortData, NumBoxCaptures, NumSphereCaptures); bool bHasBoxCaptures = (NumBoxCaptures > 0); bool bHasSphereCaptures = (NumSphereCaptures > 0); bool bNeedsClearCoat = (View.ShadingModelMaskInView & (1 << MSM_ClearCoat)) != 0; ComputeShader = SelectReflectionEnvironmentTiledDeferredCS(View.ShaderMap, bUseLightmaps, bNeedsClearCoat, bHasBoxCaptures, bHasSphereCaptures); RHICmdList.SetComputeShader(ComputeShader->GetComputeShader()); ComputeShader->SetParameters(RHICmdList, View, SSROutput->GetRenderTargetItem().ShaderResourceTexture, SortData, NewSceneColor->GetRenderTargetItem().UAV, DynamicBentNormalAO); uint32 GroupSizeX = (View.ViewRect.Size().X + AdjustedReflectionTileSizeX - 1) / AdjustedReflectionTileSizeX; uint32 GroupSizeY = (View.ViewRect.Size().Y + GReflectionEnvironmentTileSizeY - 1) / GReflectionEnvironmentTileSizeY; DispatchComputeShader(RHICmdList, ComputeShader, GroupSizeX, GroupSizeY, 1); ComputeShader->UnsetParameters(RHICmdList); } } GSceneRenderTargets.SetSceneColor(NewSceneColor); check(GSceneRenderTargets.GetSceneColor()); } void FDeferredShadingSceneRenderer::RenderStandardDeferredImageBasedReflections(FRHICommandListImmediate& RHICmdList, bool bReflectionEnv, const TRefCountPtr& DynamicBentNormalAO) { const bool bSkyLight = Scene->SkyLight && Scene->SkyLight->ProcessedTexture && ViewFamily.EngineShowFlags.SkyLighting; static TArray 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); 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(); } // Use standard deferred shading to composite reflection capture contribution for (int32 ViewIndex = 0, Num = Views.Num(); ViewIndex < Num; ViewIndex++) { FViewInfo& View = Views[ViewIndex]; bool bRequiresApply = bSkyLight; const bool bSSR = DoScreenSpaceReflections(View); TRefCountPtr SSROutput = GSystemTextures.BlackDummy; if (bSSR) { bRequiresApply = true; ScreenSpaceReflections(RHICmdList, View, SSROutput); } TRefCountPtr LightAccumulation; if (bReflectionEnv) { bRequiresApply = true; SCOPED_DRAW_EVENT(RHICmdList, StandardDeferredReflectionEnvironment); { FPooledRenderTargetDesc Desc = GSceneRenderTargets.GetSceneColor()->GetDesc(); // Make sure we get an alpha channel Desc.Format = PF_FloatRGBA; GRenderTargetPool.FindFreeElement(Desc, LightAccumulation, TEXT("LightAccumulation")); } // Clear to no reflection contribution, alpha of 1 indicates full background contribution SetRenderTarget(RHICmdList, LightAccumulation->GetRenderTargetItem().TargetableTexture, NULL, ESimpleRenderTargetMode::EClearColorToBlackWithFullAlpha); RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f); // rgb accumulates reflection contribution front to back, alpha accumulates (1 - alpha0) * (1 - alpha 1)... RHICmdList.SetBlendState(TStaticBlendState::GetRHI()); 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 > VertexShader(View.ShaderMap); // Use the appropriate shader for the capture shape if (ReflectionCapture.CaptureProperties.Z == 0) { TShaderMapRef > PixelShader(View.ShaderMap); static FGlobalBoundShaderState BoundShaderState; SetGlobalBoundShaderState(RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); PixelShader->SetParameters(RHICmdList, View, ReflectionCapture); } else { TShaderMapRef > PixelShader(View.ShaderMap); static FGlobalBoundShaderState BoundShaderState; SetGlobalBoundShaderState(RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); PixelShader->SetParameters(RHICmdList, View, ReflectionCapture); } SetBoundingGeometryRasterizerAndDepthState(RHICmdList, View, LightBounds); VertexShader->SetSimpleLightParameters(RHICmdList, View, LightBounds); StencilingGeometry::DrawSphere(RHICmdList); } } GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, LightAccumulation); } if (bRequiresApply) { // Apply reflections to screen SCOPED_DRAW_EVENT(RHICmdList, ReflectionApply); GSceneRenderTargets.BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EUninitializedColorExistingDepth, FExclusiveDepthStencil::DepthRead_StencilWrite); RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f); RHICmdList.SetRasterizerState(TStaticRasterizerState::GetRHI()); RHICmdList.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); if (GetReflectionEnvironmentCVar() == 2) { // override scene color for debugging RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); } else { // additive to scene color RHICmdList.SetBlendState(TStaticBlendState::GetRHI()); } TShaderMapRef< FPostProcessVS > VertexShader(View.ShaderMap); if (!LightAccumulation) { // should never be used but during debugging it can happen LightAccumulation = GSystemTextures.WhiteDummy; } #define CASE(A,B,C) \ case ((A << 2) | (B << 1) | C) : \ { \ TShaderMapRef< FReflectionApplyPS > PixelShader(View.ShaderMap); \ static FGlobalBoundShaderState BoundShaderState; \ SetGlobalBoundShaderState(RHICmdList, FeatureLevel, BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); \ PixelShader->SetParameters(RHICmdList, View, LightAccumulation->GetRenderTargetItem().ShaderResourceTexture, SSROutput->GetRenderTargetItem().ShaderResourceTexture, DynamicBentNormalAO); \ }; \ break switch (((uint32)bSSR << 2) | ((uint32)bReflectionEnv << 1) | (uint32)bSkyLight) { CASE(0, 0, 0); CASE(0, 0, 1); CASE(0, 1, 0); CASE(0, 1, 1); CASE(1, 0, 0); CASE(1, 0, 1); CASE(1, 1, 0); CASE(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()), GSceneRenderTargets.GetBufferSizeXY(), *VertexShader); GSceneRenderTargets.FinishRenderingSceneColor(RHICmdList); } } } void FDeferredShadingSceneRenderer::RenderDeferredReflections(FRHICommandListImmediate& RHICmdList, const TRefCountPtr& DynamicBentNormalAO) { if (IsSimpleDynamicLightingEnabled() || 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; } // 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); } else { const uint32 bDoTiledReflections = CVarDoTiledReflections.GetValueOnRenderThread() != 0; const bool bReflectionEnvironment = ShouldDoReflectionEnvironment(); const bool bReflectionsWithCompute = bDoTiledReflections && (FeatureLevel >= ERHIFeatureLevel::SM5) && bReflectionEnvironment && Scene->ReflectionSceneData.CubemapArray.IsValid(); if (bReflectionsWithCompute) { RenderTiledDeferredImageBasedReflections(RHICmdList, DynamicBentNormalAO); } else { RenderStandardDeferredImageBasedReflections(RHICmdList, bReflectionEnvironment, DynamicBentNormalAO); } } }