BackgroundBlur is difference with 5.4 and 5.6

I’ve used BackgroundBlur in Widget Blueprint.

But result is difference with UE5.4 and UE5.6

[Image Removed]

[Image Removed]

How can I make UE5.6 render as same with UE5.4 with backgroundblur?

[Attachment Removed]

Steps to Reproduce
Use BackgroundBlur on top of BackgroundBlur in widget blueprint.

The rendering result is difference between UE5.4 and UE5.6.

[Attachment Removed]

Hi,

We made some updates to use a Kawase Dual Filter blur instead of a Gaussian blur, you could try disabling that via “UI.SlatePostBlurUseDualKawaseFilter 0” to see if that explains the inconsistency. I also made some changes in CL#36281814 to apply widget scale to the corner radius set in the blur widget, it’s a bit tricky to tell how you have these widgets arranged in your hierarchy but that might be relevant here. Does reverting that change locally restore the behavior to the 5.4 example?

Best,

Cody

[Attachment Removed]

Hi, Cody.

“UI.SlatePostBlurUseDualKawaseFilter” is added on UE5.7.

I’ve reverted CL#36281814 but still rendering is difference with 5.4.

I upload a sample project including UMG having this issue on this reply.

[Attachment Removed]

Hi,

I wonder if this might be a side effect of the conversion of Slate to use RDG (CL#35454938). It’ll be tough to confirm since that was a fairly intrusive change, but we have seen some slight changes in behavior as a result since the whole underling architecture changed.

That said, it seems like the corner radius is an issue here, as your example has it turned up high enough that the smaller blur area doesn’t actually draw anything. When I adjust it down to 4 (to match the button), it looks like it’s rendering correctly:

[Image Removed]We didn’t properly scale corner radius before CL#36281814 so zooming into the widget in the designer would have caused it to be calculated incorrectly. It’s odd that reverting that change had no effect, but do you see the proper blur when you adjust the blur widget’s corner radius down to match the button?

Best,

Cody

[Attachment Removed]

You’re right. That works. Thanks for answering.

​Anyway, I’ve edited my engine code like below.

It renders well.

void AddSlatePostProcessUpsamplePass(FRDGBuilder& GraphBuilder, const FSlatePostProcessUpsampleInputs& Inputs)
{
	FSlatePostProcessUpsamplePS::FParameters* PassParameters = GraphBuilder.AllocParameters<FSlatePostProcessUpsamplePS::FParameters>();
	PassParameters->RenderTargets[0] = FRenderTargetBinding(Inputs.OutputTexture, Inputs.OutputLoadAction);
 
	if (Inputs.ClippingStencilBinding)
	{
		PassParameters->RenderTargets.DepthStencil = *Inputs.ClippingStencilBinding;
	}
	
	ESlatePostProcessUpsampleOutputFormat OutputFormat = ESlatePostProcessUpsampleOutputFormat::SDR;
 
	if (Inputs.OutputTextureToClear)
	{
		OutputFormat = Inputs.OutputTexture->Desc.Format == PF_FloatRGBA
			? ESlatePostProcessUpsampleOutputFormat::HDR_SCRGB
			: ESlatePostProcessUpsampleOutputFormat::HDR_PQ10;
 
		PassParameters->RenderTargets[1] = FRenderTargetBinding(Inputs.OutputTextureToClear, ERenderTargetLoadAction::ELoad);
	}
 
	FSlatePostProcessUpsamplePS::FPermutationDomain PermutationVector;
	PermutationVector.Set<FSlatePostProcessUpsamplePS::FUpsampleOutputFormat>(OutputFormat);
 
	const ERHIFeatureLevel::Type FeatureLevel = GMaxRHIFeatureLevel;
	FGlobalShaderMap* ShaderMap = GetGlobalShaderMap(FeatureLevel);
 
	TShaderMapRef<FScreenPassVS> VertexShader(ShaderMap);
	TShaderMapRef<FSlatePostProcessUpsamplePS> PixelShader(ShaderMap, PermutationVector);
 
	FIntVector DescSize = Inputs.OutputTexture->Desc.GetSize();
	const FIntPoint DownsampleSize = Inputs.InputTexture.ViewRect.Size();
 
	FVector2f Size = Inputs.OutputRect.Size();
	FVector2f SizeUV((DownsampleSize.X / (float)DescSize.X) - (1.0f / (float)DescSize.X), (DownsampleSize.Y / (float)DescSize.Y) - (1.0f / (float)DescSize.Y));
	
	FVector4f InputRect(Inputs.InputTexture.ViewRect.Min.X, Inputs.InputTexture.ViewRect.Min.Y, Inputs.InputTexture.ViewRect.Max.X * SizeUV.X, Inputs.InputTexture.ViewRect.Max.Y * SizeUV.Y);
	FIntPoint InputSize = Inputs.InputTexture.Texture->Desc.Extent;
	
	const FScreenPassTextureViewport OutputViewport(Inputs.OutputTexture, Inputs.OutputRect);
 
	PassParameters->ElementTexture = Inputs.InputTexture.Texture;
	PassParameters->ElementTextureSampler = Inputs.InputTexture.ViewRect == Inputs.OutputRect
		? TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI()
		: TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
 
	PassParameters->ShaderParams = FVector4f(Size, SizeUV); 
	PassParameters->ShaderParams2 = Inputs.CornerRadius;
 
	FRHIBlendState* BlendState = Inputs.CornerRadius == FVector4f::Zero() ? TStaticBlendState<>::GetRHI() : TStaticBlendState<CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_One, BF_InverseSourceAlpha>::GetRHI();
 
	FScreenPassPipelineState PipelineState(VertexShader, PixelShader, BlendState);
	GetSlateClippingPipelineState(Inputs.ClippingOp, PipelineState.DepthStencilState, PipelineState.StencilRef);
 
	GraphBuilder.AddPass(
		RDG_EVENT_NAME("Upsample"),
		PassParameters,
		ERDGPassFlags::Raster,
		[OutputViewport, InputRect, InputSize, ClippingElementsViewRect = Inputs.ClippingElementsViewRect, PipelineState, PixelShader, ClippingOp = Inputs.ClippingOp, PassParameters](FRDGAsyncTask, FRHICommandList& RHICmdList)
	{
		if (ClippingOp && ClippingOp->Method == EClippingMethod::Stencil)
		{
			// Stencil clipping quads have their own viewport.
			RHICmdList.SetViewport(ClippingElementsViewRect.Min.X, ClippingElementsViewRect.Min.Y, 0.0f, ClippingElementsViewRect.Max.X, ClippingElementsViewRect.Max.Y, 1.0f);
 
			// Stencil clipping will issue its own draw calls.
			SetSlateClipping(RHICmdList, ClippingOp, ClippingElementsViewRect);
		}
 
		RHICmdList.SetViewport(OutputViewport.Rect.Min.X, OutputViewport.Rect.Min.Y, 0.0f, OutputViewport.Rect.Max.X, OutputViewport.Rect.Max.Y, 1.0f);
 
		if (ClippingOp && ClippingOp->Method == EClippingMethod::Scissor)
		{
			SetSlateClipping(RHICmdList, ClippingOp, ClippingElementsViewRect);
		}
 
		SetScreenPassPipelineState(RHICmdList, PipelineState);
		SetShaderParameters(RHICmdList, PixelShader, PixelShader.GetPixelShader(), *PassParameters);
		FScreenPassViewInfo ViewInfo;
		UE::Renderer::PostProcess::DrawPostProcessPass(
			RHICmdList, PipelineState.VertexShader,
			0, 0, OutputViewport.Rect.Size().X, OutputViewport.Rect.Size().Y,
			InputRect.X, InputRect.Y, InputRect.Z, InputRect.W,
			OutputViewport.Rect.Size(),
			InputSize,
			ViewInfo.StereoViewIndex,
			false,
			EDRF_UseTriangleOptimization);
	});
}

Best regards,

Yun

[Attachment Removed]