// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. /*============================================================================= PostProcessLensBlur.cpp: Post processing lens blur implementation. =============================================================================*/ #include "RendererPrivate.h" #include "ScenePrivate.h" #include "SceneFilterRendering.h" #include "PostProcessPassThrough.h" #include "PostProcessing.h" #include "PostProcessLensBlur.h" #include "SceneUtils.h" /** Encapsulates the post processing vertex shader. */ class FPostProcessLensBlurVS : public FGlobalShader { DECLARE_SHADER_TYPE(FPostProcessLensBlurVS,Global); static bool ShouldCache(EShaderPlatform Platform) { return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4); } /** Default constructor. */ FPostProcessLensBlurVS() {} public: FPostProcessPassParameters PostprocessParameter; FShaderParameter TileCountAndSize; FShaderParameter KernelSize; FShaderParameter ColorScale; /** Initialization constructor. */ FPostProcessLensBlurVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FGlobalShader(Initializer) { PostprocessParameter.Bind(Initializer.ParameterMap); TileCountAndSize.Bind(Initializer.ParameterMap, TEXT("TileCountAndSize")); KernelSize.Bind(Initializer.ParameterMap, TEXT("KernelSize")); ColorScale.Bind(Initializer.ParameterMap,TEXT("ColorScale")); } // FShader interface. virtual bool Serialize(FArchive& Ar) override { bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); Ar << PostprocessParameter << TileCountAndSize << KernelSize << ColorScale; return bShaderHasOutdatedParameters; } /** to have a similar interface as all other shaders */ void SetParameters(const FRenderingCompositePassContext& Context, FIntPoint TileCountValue, uint32 TileSize, float PixelKernelSize, float Threshold) { const FVertexShaderRHIParamRef ShaderRHI = GetVertexShader(); FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View); PostprocessParameter.SetVS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); { FIntRect TileCountAndSizeValue(TileCountValue, FIntPoint(TileSize, TileSize)); SetShaderValue(Context.RHICmdList, ShaderRHI, TileCountAndSize, TileCountAndSizeValue); } { // only approximate as the mip mapping doesn't produce accurate brightness scaling FVector4 ColorScaleValue(1.0f / FMath::Max(1.0f, PixelKernelSize * PixelKernelSize), Threshold, 0, 0); SetShaderValue(Context.RHICmdList, ShaderRHI, ColorScale, ColorScaleValue); } { FVector4 KernelSizeValue(PixelKernelSize, PixelKernelSize, 0, 0); SetShaderValue(Context.RHICmdList, ShaderRHI, KernelSize, KernelSizeValue); } } }; IMPLEMENT_SHADER_TYPE(,FPostProcessLensBlurVS,TEXT("PostProcessLensBlur"),TEXT("MainVS"),SF_Vertex); /** Encapsulates a simple copy pixel shader. */ class FPostProcessLensBlurPS : public FGlobalShader { DECLARE_SHADER_TYPE(FPostProcessLensBlurPS, Global); static bool ShouldCache(EShaderPlatform Platform) { return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4); } /** Default constructor. */ FPostProcessLensBlurPS() {} public: FPostProcessPassParameters PostprocessParameter; FShaderResourceParameter LensTexture; FShaderResourceParameter LensTextureSampler; /** Initialization constructor. */ FPostProcessLensBlurPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FGlobalShader(Initializer) { PostprocessParameter.Bind(Initializer.ParameterMap); LensTexture.Bind(Initializer.ParameterMap,TEXT("LensTexture")); LensTextureSampler.Bind(Initializer.ParameterMap,TEXT("LensTextureSampler")); } // FShader interface. virtual bool Serialize(FArchive& Ar) override { bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); Ar << PostprocessParameter << LensTexture << LensTextureSampler; return bShaderHasOutdatedParameters; } void SetParameters(const FRenderingCompositePassContext& Context, float PixelKernelSize) { const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); { FTextureRHIParamRef TextureRHI = GWhiteTexture->TextureRHI; if(GEngine->DefaultBokehTexture) { FTextureResource* Resource = GEngine->DefaultBokehTexture->Resource; if(Resource && Resource->TextureRHI) { TextureRHI = Resource->TextureRHI; } } if(Context.View.FinalPostProcessSettings.LensFlareBokehShape) { FTextureResource* Resource = Context.View.FinalPostProcessSettings.LensFlareBokehShape->Resource; if(Resource && Resource->TextureRHI) { TextureRHI = Resource->TextureRHI; } } SetTextureParameter(Context.RHICmdList, ShaderRHI, LensTexture, LensTextureSampler, TStaticSamplerState::GetRHI(), TextureRHI); } } }; IMPLEMENT_SHADER_TYPE(,FPostProcessLensBlurPS,TEXT("PostProcessLensBlur"),TEXT("MainPS"),SF_Pixel); FRCPassPostProcessLensBlur::FRCPassPostProcessLensBlur(float InPercentKernelSize, float InThreshold) : PercentKernelSize(InPercentKernelSize), Threshold(InThreshold) { } void FRCPassPostProcessLensBlur::Process(FRenderingCompositePassContext& Context) { SCOPED_DRAW_EVENT(Context.RHICmdList, PassPostProcessLensBlur); const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0); if(!InputDesc) { // input is not hooked up correctly return; } const FSceneView& View = Context.View; FIntPoint TexSize = InputDesc->Extent; // usually 1, 2, 4 or 8 uint32 ScaleToFullRes = GSceneRenderTargets.GetBufferSizeXY().X / TexSize.X; FIntRect ViewRect = FIntRect::DivideAndRoundUp(View.ViewRect, ScaleToFullRes); FIntPoint ViewSize = ViewRect.Size(); const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context); // Set the view family's render target/viewport. SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef(), ESimpleRenderTargetMode::EClearColorToBlack); Context.SetViewportAndCallRHI(ViewRect); // set the state (additive blending) Context.RHICmdList.SetBlendState(TStaticBlendState::GetRHI()); Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); TShaderMapRef VertexShader(Context.GetShaderMap()); TShaderMapRef PixelShader(Context.GetShaderMap()); static FGlobalBoundShaderState BoundShaderState; SetGlobalBoundShaderState(Context.RHICmdList, Context.GetFeatureLevel(), BoundShaderState, GEmptyVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); uint32 TileSize = 1; FIntPoint TileCount = ViewSize / TileSize; float PixelKernelSize = PercentKernelSize / 100.0f * ViewSize.X; VertexShader->SetParameters(Context, TileCount, TileSize, PixelKernelSize, Threshold); PixelShader->SetParameters(Context, PixelKernelSize); Context.RHICmdList.SetStreamSource(0, NULL, 0, 0); // needs to be the same on shader side (faster on NVIDIA and AMD) int32 QuadsPerInstance = 4; Context.RHICmdList.DrawPrimitive(PT_TriangleList, 0, 2, FMath::DivideAndRoundUp(TileCount.X * TileCount.Y, QuadsPerInstance)); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); } FPooledRenderTargetDesc FRCPassPostProcessLensBlur::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = PassInputs[0].GetOutput()->RenderTargetDesc; Ret.Reset(); // more precision for additive blending Ret.Format = PF_FloatRGBA; Ret.DebugName = TEXT("LensBlur"); return Ret; }