Circular Progress Bar with Rounded Ends in Unreal Engine 5

August 26, 2026•9 min read

Download the project files here:

Google Drive Link


Watch the Entire Process Here:


Consider my Unreal Engine Horror Course!

Click here to check out the details on my full-length course on creating a horror game from scratch in Unreal Engine.


Written Steps:

1. Build the Radial Progress Material from a Gradient

1.1 Create a User Interface Material

Create a new material and name it something like M_RadialProgressBar. Open the material and change its material domain from Surface to User Interface. Enable Show Border in the preview window so the texture limits remain visible while you build the graph.

Change the blend mode from Opaque to Translucent. This enables the material to use the opacity output for the transparent areas around the ring.

Custom HTML/CSS/JavaScript

1.2 Generate and Control a Radial Gradient

Add a Vector to Radial Value node and connect its output to Final Color. The node creates an angular gradient that starts at 0 and reaches 1 across a full 360-degree rotation.

Add a Step node and connect the radial value to it. The Step node turns the continuous gradient into a visible progress section. Its threshold controls how much of the circle remains filled. Values such as 0.1, 0.5, and 1.0 create small, half, and full progress states.

Create a scalar parameter named Progress. Keep its range between 0 and 1, since this value will control the bar during gameplay.

2. Turn the Radial Fill into an Adjustable Ring

2.1 Create the Circular Masks

Add a Radial Gradient Exponential node and connect it to Final Color while testing. This creates a circular mask, but its edge may look too soft at first.

Create a constant with the 1 key and a mouse click, then connect it to the node's density input. A value near 300 creates a sharp edge without the artifacts that can appear with extremely high values. A lower value, such as 100, leaves the circle softer.

Connect the circular mask to Opacity and return the Step output to Final Color. At this point, the progress appears as a pie chart.

Duplicate the radial gradient node to create the hollow center. Keep the outer circle radius at 0.5, which reaches the texture boundary. Set the inner circle radius to about 0.3, then use a Subtract node to subtract the inner circle from the outer circle. The result is the ring mask for the radial progress bar.

2.2 Expose Bar Thickness

The inner circle controls the ring thickness. A larger inner radius makes the ring thinner, while a smaller radius makes it thicker.

Create a scalar parameter named Thickness and set its slider maximum to 1. Invert it with a 1 - Thickness node, then multiply the result by 0.49. Using 0.49 instead of 0.5 prevents the ring from disappearing at the thinnest setting.

A thickness value of 0 creates the thinnest ring. A value of 1 reduces the inner radius to nearly zero, producing a pie-chart-like fill. Save the converted radius with a Named Reroute node so you can reuse it for the rounded tips.

2.3 Calculate and Place the Rounded Caps

Rounded ends come from two small filled circles placed on the ring's endpoints. Their radius must equal half the ring's diameter.

First, subtract the inner radius from the outer radius:

Ring Diameter = 0.5 - InnerRadius

Then divide the result by 2:

Tip Radius = Ring Diameter / 2

Save this value to a Named Reroute called ThicknessRadius. Use another Radial Gradient Exponential node with a density near 300, and connect ThicknessRadius to its radius input.

The first tip begins on the right side of the texture. Create a center position using texture coordinates that run from 0 to 1. Set the X value to 1.0, subtract ThicknessRadius, and keep Y at 0.5. Use an Append Vector node to create the final position.

Add this small circle to the ring mask. It should now sit neatly on the right edge, with its center adjusted so the circle does not extend past the texture border.

2.3 Rotate the Ending Tip with Progress

Duplicate the small circle setup for the second endpoint. Add a Custom Rotator node and connect Texture Coordinates to its UV input. Set the rotation center to (0.5, 0.5) so the cap rotates around the center of the full texture.

The ending tip must follow the current progress value. Convert the progress rotation with 1 - Progress, then feed that result into the Custom Rotator's rotation angle. Add the second tip to the first with an Add node, then combine both tips with the main ring mask.

Test values such as 0.3, 0.6, and 0.8. The second rounded cap should move with the end of the filled section while the first cap stays at the starting point.

3. Add Rotation, Colors, and Transparency

3.1 Rotate the Entire Bar

The default radial gradient starts on the right. To move the start point to the top, add another Custom Rotator before the Vector to Radial Value node.

Connect Texture Coordinates to the rotator and use (0.5, 0.5) as the pivot. Since the radial node already applies an internal offset, subtract 0.5 from the coordinates where needed before rotating them.

Create a scalar parameter named EntireBarRotation with a range of 0 to 360. Divide the degree value by 360 to convert it into the 0 to 1 range expected by the material. Add 0.25 as the default offset if the bar should start at the top.

Use -360 instead of 360 if you prefer the value to move clockwise. Apply this same rotation to both rounded tip rotators so the endpoints stay aligned with the ring.

3.2 Blend Colors and Preserve Alpha

Add a Linear Interpolate node to blend the background and filled sections. Create vector parameters named BackgroundColor and FillColor, then connect them to the Lerp inputs. Use the progress ring mask as the Lerp alpha and connect the result to Final Color.

To support transparent colors, include the full RGBA output from the color parameters. Mask the alpha channel and multiply it by the ring and tip mask before connecting it to Opacity.

The two rounded tips can overlap, producing values above 1 where their masks are added together. Place a Saturate node after the combined mask. Saturate clamps the result between 0 and 1, removing dark overlap artifacts and keeping transparency working as expected.

4. Package the Radial Progress Bar as a Reusable Widget

4.1 Create a Dynamic Material Instance

Create a Widget Blueprint named RadialProgressBar and add an Image widget. Set its display mode to Desired and enable the image as a variable.

On the Pre Construct event, create a Dynamic Material Instance using M_RadialProgressBar. Promote it to a variable named RadialProgressBarMat, then use Set Brush from Material to apply it to the Image widget.

A Dynamic Material Instance is required for runtime changes. A regular material instance can store parameter values, but Blueprint code cannot change those values during play unless the material is dynamic. Pre Construct also lets the material appear in the Widget Designer.

4.2 Add Runtime Controls

Create setter functions that update the Dynamic Material Instance. SetProgress should call Set Scalar Parameter Value with the parameter name Progress. Add similar fu4nctions for Thickness and EntireBarRotation.

Create a SetBarColors function that calls Set Vector Parameter Value for BackgroundColor and FillColor. Parameter names must match the material exactly, including capitalization and spelling.

Expose the user-facing progress, color, thickness, and rotation values in the widget. Clamp progress and thickness between 0 and 1, and clamp rotation between 0 and 360. Keep the material reference and internal state private so outside Blueprint code uses the setter functions instead of bypassing the update logic.

Add the widget to your HUD and keep its layout square. A non-square image can stretch the circle into an oval.

5. Test the Finished Widget

5.1 Drive Progress During Gameplay

Store the radial progress widget as a variable in the HUD, then call its SetProgress function during play. For a quick test, use game time in seconds and pass it through a sine wave.

A sine wave returns values from -1 to 1. Add 1, then divide by 2 to convert the result to the required 0 to 1 range:

Progress = (sin(GameTime) + 1) / 2

Connect that value to SetProgress. When you press Play, the bar should expand and contract continuously.

5.2 Hide the Bar at Zero Progress

At zero progress, the two endpoint circles can overlap and leave a small visible remnant. If the bar should vanish completely, add an If node to the fill or color alpha logic.

Compare Progress against 0.01. When progress is below that value, output 0. At 0.01 or higher, continue using the normal mask. This gives you a clean hidden state without changing the rounded-cap setup.

Set useful defaults in the Designer, such as progress around 0.6, a readable thickness, a rotation of 0, a muted background color, and a bright fill color. Compile and save before placing new instances in your HUD.

Conclusion

This Unreal Engine radial progress bar uses a small set of material nodes to create a flexible UI control. Vector to Radial Value provides the angular gradient, Step controls progress, and two radial masks form the hollow ring. Small circles create rounded tips, while Custom Rotators keep them aligned with progress and bar rotation.

The Widget Blueprint turns the material into a reusable component. A Dynamic Material Instance handles runtime changes, while setter functions control progress, thickness, colors, and rotation. Add the widget to your HUD, test it with live values, and apply the near-zero check if the bar must disappear cleanly at zero.

unrealwidgetenginemovementstatemachinecrouchslideadvancedcapsule
Back to Blog
DreadEngine Technical Logo

© 2026 GeckoGameDev. All Rights Reserved.