Top-Down Fog of War in Unreal Engine, Part 1: The Post-Process Setup

Part 1 of building top-down fog of war in Unreal Engine: a Fog Manager actor that feeds a post-process material, plus the floor mask and player spotlight.

This is the first part of a tutorial series on building top-down fog of war in Unreal Engine. In this video I go over how I set up a simple actor that creates a fog of war post-process volume and sends data from the world into a post-process material.

I consider this an intermediate guide. You should be comfortable with simple C++ and common pieces like the post-process volume and render targets. By the end you will be able to set up your own fog of war post-process volume with a spotlight around the player, exactly as shown in the video above.

The Fog Manager actor

The main actor responsible for setting up the post-process volume is called BPFogManager. We open its blueprint and go straight to its C++ parent, which is where the real work happens. This class sets up the global post-process volume and applies the fog material to it.

BP_FogManager actor selected in the Unreal Engine level outliner

Constructor: an unbound post-process volume

In the constructor we create the post-process volume component and set its bUnbound flag to true, so that the volume encompasses the entire world rather than just the area inside its bounds. That single setting is what lets the fog cover the whole map.

The AFogManager C++ constructor creating a post-process volume component with bUnbound set to true

BeginPlay: a dynamic material instance

In BeginPlay we create a dynamic instance of the fog material so that we can pass live world values to it at runtime, then apply that instance to the post-process volume.

BeginPlay creating a dynamic material instance and applying it to the post-process volume

Tick: feeding the player’s normalized location

Every tick, we send the current location of the locally controlled character to the fog material. Materials and textures mostly work with normalized values between 0 and 1, so we divide the character’s world location by the world size to get a normalized value before passing it in.

The Tick function sending the character's normalized location to the fog material

The fog material

Back in the fog manager, we can now look at the fog material itself. At its core the material comes down to three things: a dark shadow color, a regular (lit) color, and a mask that decides what is dark and what is light.

The fog of war post-process material graph in the Unreal Engine material editor

How the masks combine

That mask is really several black-and-white masks combined together. It only returns white for the parts of the map that can receive light, and where either the local player or one of their beacons is at the moment.

To keep this video concise, we focus on the two primary masks first: the floor mask and the player spotlight. The more complex ones, such as beacon spotlights and the player shadow mask, come in later videos.

The combine masks section of the material graph, with the floor mask and player spotlight labelled as the primary masks

The floor mask

To understand the floor mask, we switch to another map. Here we have a floor where only the dark gray parts are walkable by the player. We do not want the non-walkable parts to receive light.

A top-down test map where only the dark gray floor areas are walkable

The walkable render target

We have a render target that returns a black-and-white mask of this map, where only the walkable floors are white. (How that mask is generated is covered in a related video.) We apply this as the floor mask in the fog material.

A render target asset that stores a black-and-white mask of the walkable floor

Sampling the mask in normalized space

In the texture sample node we read the mask’s pixels in normalized coordinates between 0 and 1. In the pink part of the graph we take the world coordinates and divide them by the map size to normalize them the same way.

A Texture Sample node reading the walkable mask in the material graph

Two kinds of world origin

We handle two kinds of world here. In the first, the coordinates are always positive, so we simply divide the pixel’s absolute world position by the map size to get its location in the 0 to 1 range.

In the second, the coordinates run from a negative value to a positive one. We do exactly the same thing, but first we add half the world size to shift the pixels from a minus 0.5 to 0.5 range up into the 0 to 1 range.

The material graph handling both a positive (cornered) world origin and a centered world origin

Output to a Named Reroute

Finally, we output the floor mask to a Named Reroute node (a “portal”), which we later use in combination with the rest of the masks. Named Reroutes keep the graph readable instead of dragging wires across the whole material.

The floor mask routed into a Named Reroute output node

The player spotlight

A quick refresher on how the data flows: the Fog Manager communicates world information to the fog material. In BeginPlay it sends the map size and the character’s visibility radius, and in tick it sends the character’s UV location. The material reads those parameters back out.

The Fog Manager C++ sending map size and visibility radius to the material

From those parameters we build a black mask with a single white sphere at the character’s location. Just like the floor mask, we output it through a Named Reroute so it is ready to combine with the others.

The player spotlight nodes reading the manager parameters to draw a white sphere at the player

Combining the masks

Now that we understand the floor mask and the player spotlight, we can combine them to create light around the player. We use a min node so that a pixel is only white where both masks are white: the player has to be standing on walkable floor for that floor to light up.

A min node combining the floor mask and the player spotlight in the material graph

We also add a saturate node to make sure the mask values stay clamped between 0 and 1.

A saturate node clamping the combined mask between 0 and 1

The result

Dropping the Fog Manager into the scene, we now have a simple spotlight that lights the walkable floor around the player’s location.

The finished fog of war effect: a spotlight lighting the floor around the player in the Unreal editor

What’s next

That is the foundation: an unbound post-process volume, a material driven by live world data, and two masks combined into light around the player. In the next parts we go further with the more complex masks, including beacon spotlights and the player shadow mask.

If you would rather drop this into your project ready-made, the Multiplayer Fog of War plugin packages all of this up, replicated and performance-minded, for multiplayer and single-player top-down games.