How can we make a soft drop shadow for a UMG Image?

Hey there

I’m working on building a set of UMG components that follow the android material design specification, and I’ve been racking my brains trying to figure out how I can create the key and ambient shadows as described here:

[Android Material Design: Shadows][1]

What I have, so far:

So far, I’ve got a simple widget set up which uses 3 different Image components to draw the “Surface”, “Ambient Shadow” and “Key Shadow”, like below:

263005-hierarchy.png

The Brush that draws the Images uses a Box-scaled dynamic material as its resource, since I’d like the designer to alter the shape/roundedness of the widget at any time:

263006-brush.png

And the material parameters are exposed via Blueprint to the designer:

263007-widgetvariables.png

My Brush material is set up to use a Distance Field Texture and uses the Packed Distance Field node to draw the texture at good detail without worrying about pixelation due to scaling:

And I set the “edge softness” property to a specific value to fake a “blur” effect on the texture, which I then use on the Shadow image, in conjunction with padding, to give it a feel of “elevation”, as described in the material design spec.

(The UV scaling nodes simply correct the change in shape of the image due to softening).

Now, the issues that I’m facing with this approach are:

  • I end up creating at least 3 different dynamic materials per instance of this widget, which is pretty bad for performance with a large number of them instantiated in the game.

  • There is a lot of overdraw, most of it unnecessary, which is also terrible for performance on mobile devices.

  • Since the image is Box-scaled, the edge softness parameter barely has an effect, and the result looks nothing like I need it to:

As you can see, the shadow Images don’t have softened edges and look quite jarring, as opposed to the design specified by Google.

Question:

So, does anyone have any ideas for how one can create soft-shadows for an image in UMG, with a smooth falloff that is also good performance-wise?

Additional Info:

CSS Box shadow values for the Material Design Components at different elevations can be found at the following link, in case that helps:

[Material Elevation CSS Box Shadow Values][8]

Thanks in advance!

1 Like

Hello RahuloftheRamanEffect

Did you find the correct solution to create dynamic shadow for images or entire widget?

Thanks

1 Like

No luck yet.
I noticed that UE4 editor just uses a couple of generic textures to create a drop shadow effect on different UI elements, but they only really work for rectangles.

Maybe the thing to do would be to dynamically generate a bunch of textures when the widget shape is modified and use them to represent the shadow. I am yet to attempt this.

1 Like

Any luck on finding the solution?

1 Like

Unfortunately I don’t know how to make a soft shadow only in Unreal.

However, I found another way to add shadows to images. I wrap the image in an overlay and duplicate it in it. In the duplicated object I then set my desired color and opacity. Lastly I use the translation to move the image so that it becomes a shadow.

You can then turn the shadow image into a soft shadow in a graphics program if you want.

I hope this helps others reading this post too.

1 Like

There are multiple ways to achieve shadows, such as Gaussian blur.
In this plugin I used a different approach by calculating the distance from a point to a rectangle to determine the color of the shadow.

For specifically the use case of a box with rounded corners, I have two materials to share. For both, I am using 2-3 different instances of “Generated Round Rect” to produce the masks for the shadows, and using the “Sharpness” setting to control the blur of the shadow. It’s a bit crude because the shadows aren’t quite as soft as I’d like, but it comes pretty close to the UI mock-ups I was trying to implement here.

The first material is a simple box with a drop shadow, like you’d use on a button:

The second material is a box that has an inner shadow with a border around the whole thing, like you’d use on a text field:

You should be able to use both of these with the “Box” image mode of buttons and text fields. The “margin” setting of the image is extremely important and finicky, and I haven’t yet figured out how to make the setting behave in a predictable way. The value you use for “margin” is affected by the “box width”, “box height”, and “corner ratio” settings in the material, as well as the “image size” setting in the UMG widget.

Here’s an example of the first material with image size 64x64, margin 0.5, box width 0.75, box height 0.75, and corner ratio 0.25:

Here’s an example of the second material with image size 512x256, margin 0.125, box width 0.9565, box height 0.9, and corner ratio 0.7 (pictured here with shadow offset X of 0.62, shadow offset Y of 0.61, and shadow sharpness of 0.05):

1 Like

I ended up reworking the blueprint for the text field with the inner shadow. Now, the border and shadow calculations are a lot more deterministic.

Here’s an example of the textbox material with image size 1024x1024, margin 0.5, 0.075 (NOTE: The horizontal and vertical margins are different), box width 0.96, box height 0.96, and corner ratio 0.65 (pictured here with shadow offset X of 2.5, shadow offset Y of 5.0, shadow scale of 1.5, and shadow sharpness of 0.0):

The blueprint link is the same as before:

If you would like the simplest, cheapest drop shadow you will have to exclude shadow softness:

There will be a shadow softened version below, based on my experience, the performance impact does exist for sure, but its not a huge deal if your not using it for every widget.

There are those who said this day would never come. What are they to say now?

16 SAMPLES WITH GRADIENT SOFTENING BABY!

This material works by taking multiple copies of the image texture alpha and slightly shifting them in different directions to create a smooth, soft shadow effect. Each sample is taken at an offset position around the original UV coordinates in a circular pattern, ensuring even distribution. To make the shadow fade naturally, the distance of each sample from the center is calculated, and a smooth transition is applied using a Smoothstep function, which gradually reduces the opacity of samples farther from the center. After applying this fading effect, all 16 samples are averaged together, blending them into a seamless, blurred shadow. This method mimics a Gaussian blur by ensuring the shadow spreads evenly in a semi circular pattern.

I’m not sure how much 16 texture samples plus the actual image, plus the center piece will affect performance, but this seems to be the only option.

Anyway here is the link to the material:

God–it’s–it’s–beautiful

Last but not least, i also created a 32 sample one. I would reccomend sticking with the 16 sample one if possible, the difference isnt very noticeable, but it uses twice the samples.

Starting to look like a neural network lol

2 Likes

This material function generates a rounded rectangular shape with a controllable border thickness, corner roundness, and anti-aliasing smoothing, all centered in UV space.

It uses Signed Distance Fields (SDF) to render smooth, resolution-independent shapes directly in the material, making it ideal for custom UI.

DISCLAIMER: I cannot upload as a text file or even on blueprint UE (I’m assuming because of the Border material functions so you will have to follow along lol

First we need to create the border material function.

(Material Function)

MF_Border Blueprint UE Paste

Now we need to create a modified version of the drop shadow material. Since my material setup is currently very messy.

Here’s what you need to do:

Start with the original drop shadow material – using 16 samples should be ideal for good results.

Locate the image texture nodes in the material.

These image textures will have a UV input.

Hold Ctrl and drag the UV input from the image texture node into the UV input of the Border Material Function.

Take the Opacity output and connect it to the Multiplier input of the corresponding Smoothstep node.

Now repeat that step for EVERY texture sample used for the drop shadow (Not the one that goes into the final color)

Delete the corresponding texture samples and texture object when finished.

Now we need to replace the final texture sample with the actual border itself.

And finally, assuming you want the border parameters for the drop shadow border material function (Which you absolutely more than likely do)–this is a very tedious step.

First, create the following parameters that will be fed into the border samples
(Make sure the inputs are the correct type, color is a vector 3, and the rest are scalars):

Now the tedious part, you need to hook these inputs into EVERY sample, including the final border itself:

Speaking of performance, this likely is alot heavier because it is drawing the border 17 times with logic (a texture sample will always be cheaper).

As always with optimization, if it runs fine, then use it.

Great for confirmation widgets (Which is why i created it)

1 Like