Implementation Question for UI Drop Shadow

Hello, everyone. I have been trying to implement a drop shadow for my game’s User Interface, but I’ve hit a roadblock when it comes to my understanding of UE4 and I was hoping I could get some advice.

Implementation
Based on the css drop-shadow function (Mozilla’s Example) I came to this understanding of how a drop shadow is made.

  1. Copy the image that the shadow is being made from
  2. Based on the blur radius add a border twice the that number in thickness around the copy with every pixel having an alpha of 0.
  3. Change the RGB value of every pixel in the copy to the input color for the shadow.
  4. Create a copy of the copy. The copy’s copy will be the drop shadow.
  5. Apply the Gaussian Blur to the alpha values of the copy and change the values in the shadow based on the results.
  6. Center your shadow behind the image.
  7. Offset the shadow by the offset parameters.

I’m confident I could do this with in a web browser, but I’m stumped on how to do it UE4. I’ve tried finding a solution with UMG, Materials, and Slate, but ran into roadblocks with all three. I hope that someone could give me some hints on what to do next.

UMG
The easiest way forward was to stack an image on top of a copy of itself and have a background blur stuffed in between. Needless to say, there is an issue with this method. The background blur has to extend past the edges of the image. If you don’t have a flat color behind and around the background blur it will ruin the shadow effect.

Is there an available widget that I am missing that would apply a similar effect to only one widget?

Materials
I tried learning more about materials to see if I could make something to plug into a widget image, but all the blur solutions I found were for 3d. The material only needs to be for the shadow and it’s very easy to change the color of a material. The problem I’m having is changing the size of a material/texture based on the blur radius.

Is there a node that adds blank space instead of cropping or expanding?
If not, can this be done accurately with the custom node?
Is it even possible to begin with?

Slate
After trying to figure things out with materials, I tried figuring it out with Slate. I had a bad time. Going to the source code for the Background Blur class, I tried figuring out where the Gaussian Blur was implemented/applied. Following the values passed through the widget, I jumped from function to function.

  1. BackgroundBlur.cpp (Line 44) –> SBackgroundBlur.cpp
  2. SBackgroundBlur::OnPaint() (Line 151) –> DrawElements.cpp
  3. FSlateDrawElement::MakePostProcessPass (Line 574) –> ElementBatcher.cpp (Used the ‘Find All’ tool for this connection)
  4. FSlateElementBatcher::AddPostProcessPass (Line 2274) –> ???

At this point, I thought it would be better to ask for help as I’m not really sure where the render trail goes from here and implementing the widget appears to be much more complex than I originally thought it would be.

Where does the Render path go from here?
Should I try to figure it out with a snapshot from stat unit?
Is the way that I am describing the implementation even the proper way to go about it in this engine?
If you don’t want to give me the answer, can you point me in the right direction in terms of what I need to learn?

Thanks in advance to anyone who replies to this post.

2 Likes

Hey @anonymous_user_4afb1bf91, I noticed you didn’t receive an answer to your drop shadow question but your question is one of the top results when I tried figuring out the same thing. I found a solution that works for me I thought I would share. It’s only C++ though so sorry for anyone wanting to use UMG blueprints, but I think the same effect could be achieved there too with a similar approach.

  1. Create a UBorder to function as the drop shadow and set the image to Slate’s drop shadow asset. Also set the Padding in any direction so it shows (I prefer bottom and right side).
UBorder* shadowBorder = NewObject<UBorder>();
shadowBorder->SetBrush(*FAppStyle::Get().GetBrush("ContentBrowser.AssetTileItem.DropShadow"));
shadowBorder->SetPadding(FMargin(0, 0, 2.0f, 2.0f));
  1. Create another UBorder and add it as the shadowBorder’s content.
UBorder* contentBorder = NewObject<UBorder>();
shadowBorder->SetContent(contentBorder);
  1. Add any content you want to contentBorder. Here’s an example of adding a UTextBlock.
 UTextBlock* myTextBlock = NewObject<UTextBlock>();
 myTextBlock->SetText(FText::FromString("Example"));
 contentBorder->SetContent(myTextBlock);

You can then put shadowBorder as the child of any other UMG widget. In my class specifically, I inherited UBorder and made the base instance the shadowBorder. For reference I got this idea by looking class that adds the drop shadows to asset items in the Content Browser. Check out AssetViewWidgets.cpp around line 148:

// Folder base
		ItemContentsOverlay->AddSlot()
		.Padding(FMargin(5))
		[
			SNew(SBorder)
			.BorderImage(FAppStyle::Get().GetBrush("ContentBrowser.FolderItem.DropShadow"))
			.Padding(FMargin(0,0,2.0f,2.0f))
			[
				SNew(SImage)
				.Image(FolderBaseImage)
				.ColorAndOpacity(InTileOrListItem, &T::GetAssetColor)
			]
		];

If you want the shadow to overlap other items, I think the whole thing could be placed in an OverlayPanel with other widgets. I’ve not tried that specifically so it may take some experimentation.