[TUTORIAL] Fog Of War

Hey Milotron, thank you a lot for this standalone project, it makes it really easy to study principles of FOW and implement it into your own poroject ! And of course THANKS to **** for this great FREE AND OPEN solution!
I just want to put my 5 cents into this project; on UE 4.14.3 I experiencied a crash while launching FOW project on standalone game mode with EnablePostProcess set to ON in LevelInfo_BP:


MachineId:A06E43CE4CF1C48A0533C49DB547D1D4
EpicAccountId:333cfc2535634313bd4d2bff030c90c3

Access violation - code c0000005 (first/second chance not available)

nvwgf2umx
nvwgf2umx
nvwgf2umx
d3d11
UE4Editor_D3D11RHI!FD3D11DynamicRHI::RHIUpdateTexture2D() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\windows\d3d11rhi\private\d3d11texture.cpp:1540]
UE4Editor_RHI!FDynamicRHI::UpdateTexture2D_RenderThread() [d:\build\++ue4+release-4.14+compile\sync\engine\source\runtime\rhi\private\rhicommandlist.cpp:1966]
UE4Editor_O2Project_5697!`AFogOfWarManager::UpdateTextureRegions'::`5'::EURCMacro_UpdateTextureRegionsData::DoTask() [e:\unreal\o2projectnew\source\o2project\fogofwarmanager.cpp:241]

I don not know why, but in standalone mode in AFogOfWarManager something goes wrong with LastFOWTexture->UpdateResourceW() (be consequence it pass incorrect result into AFogOfWarManager::UpdateTextureRegions and as following - in RHIUpdateTexture2D). My simple solution is just to not perform LastFOWTexture->UpdateResourceW() on first tick with an additional bool variable and the following modification of code:


void AFogOfWarManager::Tick(float DeltaSeconds) {
	Super::Tick(DeltaSeconds);

	if (FOWTexture && LastFOWTexture && bHasFOWTextureUpdate && bIsDoneBlending) {
		if (!bFirstFOWTextureUpdate) { //do not UpdateResource for LastFOWTexture on first tick
			bFirstFOWTextureUpdate = true;
		}
		else {
			LastFOWTexture->UpdateResourceW();
		}
		UpdateTextureRegions(LastFOWTexture, (int32)0, (uint32)1, textureRegions, (uint32)(4 * TextureSize), (uint32)4, (uint8*)LastFrameTextureData.GetData(), false);
		FOWTexture->UpdateResourceW();
		UpdateTextureRegions(FOWTexture, (int32)0, (uint32)1, textureRegions, (uint32)(4 * TextureSize), (uint32)4, (uint8*)TextureData.GetData(), false);
		bHasFOWTextureUpdate = false;
		bIsDoneBlending = false;
		//Trigger the blueprint update
		OnFowTextureUpdated(FOWTexture, LastFOWTexture);
	}
}

Hope it helps others suffering the same issue with FOW, and it would be great if Milotron could includ this (or a better one) fix into his sample project :rolleyes:

Fork + Time
everyone, i an earlier post i said i was going to share where i made the modifications to the code, so i drew a couple of pictures explaining the way i think the code works, and where i made the modifications, this is just a tool for newcomers and people with no so advanced coding abilities, like me.

In the most simple way, the FOW in this project works using two arrays, a Boolean array and a FColor array, the picture above shows those arrays in Two different states, before an actor movement and after.
The bool array is black and white, and the FColor in the picture is light blue
If anyone is trying to understand the code, i think that a good start is in the FogOfWarWorker.cpp where most of the operations are performed, and the picture above is a simple (simple) representation of the code in that file.

The modifications made (purple color in the picture) by me are just a few IF statements that prevent or allow execution of code or data storage . The first one is made before the code checks the vectors in the sight of the actor, this is


if (isWriteUnFog) {

The second modification prevents/allows writing new values to the Bool Array named UnfoggedData


if (isWriteTerraIncog){

The other changes made, like the ability to load images as masks, and checking if the actor is “in some part of the texture” are easy to follow once one understand, and in my case if one draws what is happening with these two arrays.

Also…
I have made a new modification to this project thinking in the FOW mechanic, and in a new way to play with it. It is something simple, a timer recording the FOW “age” or how long ago the registered actors were in a particular position
for this i created two additional arrays, a boolean array tagging positions that should have a timer, this array is used inside the Worker thread, a second array containing the time values, this array is outside the worker thread and it gets the delta time after the last tick. Here is a video showing the timer with a limit, after the limit time has been reached the unveiled values that are not in sight (FOW) will return to black (What i call TerraIncognita)

And the picture explaining what is happening inside the code

The project files are here <=======

I hope anyone trying to program their own FOW solution finds this ideas useful, by doing this modifications I was thinking on how the fog of war is also a type of representation of memory, and with the timer the part of forgetting the information of a place. Well, that’s it.

Also thanks to for the FOW manager, as said by others before, it is also a good source of information on how to use threads. :slight_smile:

rainman85, i don’t know if I changed something in the new code but can’t reproduce the error, i will keep checking if a get this error. Sometime ago i had constant crashes exiting the game, but posted in the first page a couple of lines that fixed those crashes.
I will include your fix in the next version, along some other parts i left half broken.
:slight_smile:

I am having trouble with this in 4.15. It still crashes in the same spot as in Rainman85’s post #141 but the fix doesn’t work for me. The crash doesn’t seem to happen always.

I also made some changes:



	if (FOWTexture && LastFOWTexture && bHasFOWTextureUpdate && bIsDoneBlending) 
	{
		for (int32 i = FowActors.Num() - 1; i >= 0; i--)
		{
			if (!FowActors* || FowActors*->IsPendingKill())
				FowActors.RemoveAt(i);
		}

		if (bShouldReset)
		{
			int arraySize = TextureSize * TextureSize;
			TextureData.Init(FColor(0, 0, 0, 255), arraySize);
			LastFrameTextureData.Init(FColor(0, 0, 0, 255), arraySize);
			HorizontalBlurData.Init(0, arraySize);
			UnfoggedData.Init(false, arraySize);
			bShouldReset = false;
		}

		LastFOWTexture->UpdateResource();
		UpdateTextureRegions(LastFOWTexture, (int32)0, (uint32)1, textureRegions, (uint32)(4 * TextureSize), (uint32)4, (uint8*)LastFrameTextureData.GetData(), false);
		FOWTexture->UpdateResource();
		UpdateTextureRegions(FOWTexture, (int32)0, (uint32)1, textureRegions, (uint32)(4 * TextureSize), (uint32)4, (uint8*)TextureData.GetData(), false);
		bIsDoneBlending = false;
		//Trigger the blueprint update
		OnFowTextureUpdated(FOWTexture, LastFOWTexture);

		bHasFOWTextureUpdate = false;
	}


I added Reset() function that just sets bShouldReset = true; and I moved bHasFOWTextureUpdate to the bottom. If bHasFOWTextureUpdate is set earlier the worker thread could start updating the textures before OnFowTextureUpdated is even done. I don’t have Rainman85’s fix applied right now because I didn’t notice any difference to crashes with it applied.

Is there any test I can do on the texture to make sure it’s fully initialized when UpdateTextureRegions is called? I am attempting checks like “IsFullyStreamedIn()” and checking that the texture sizes are the same as what was intended, but I am not sure if those are the right way to do it. Also, how does ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER() work? Does it do the rendering in a separate thread? Does it send a copy of the data or just a reference. If it sends the rendering thread a reference of the data, couldn’t the data be changed or even destroyed before the rendering is finished?

Hey , thanks a lot for the great tutorial and work!

Is it possible, to make the fog disappear by an object? Example i put a torch at some point, and in a radius of 10 meters, the fog will disappear because of the torch, not because i look and run in the fog.
Hope you know what i mean ^^

next time i should watch the entire video ->instead using a stone/rock i can use my own object :slight_smile:

Is the latest project made with 4.14.3? Because i tried with 4.16, 4.15 and 4.14.3 and allways getting the same error. UnrealEngine tries to compile and than crash with some missig files.

Great article!

I can confirm that the circle algorithm is very… slow especially with more than 10 or so actors and the midpoint algorithm is extremely fast. (Also, I cannot understand why the Trace is needed?)
Please see below a modified filled midpoint circle and tell me if it can fit to your implementation. I can say that it works with your Post process material.

Thank you for all your efforts.

void AFowActor::MidpointFilledCircle(const FVector Location, const float SightRange)
{
int X = FMath::RoundToInt(SightRange * SamplesPerMeter);
int Y = 0;
int RadiusError = 1 - X;

uint32 HalfTextureSize = TextureSize / 2;
float Dividend = 100.f / SamplesPerMeter;

FIntPoint Tile;
//We divide by 100.0 because 1 texel equals 1 meter of visibility-data.
Tile.X = (int)(Location.X / Dividend) + HalfTextureSize;
Tile.Y = (int)(Location.Y / Dividend) + HalfTextureSize;

while (X &gt;= Y)
{
	ShowRow(Tile, -X, X, Y);
	if (Y != 0)
	{
		ShowRow(Tile, -X, X, -Y);
	}

	++Y;

	if (RadiusError &lt; 0)
	{
		RadiusError += 2 * Y + 1;
	}
	else
	{
		if (X &gt;= Y)
		{
			ShowRow(Tile, -Y + 1, Y - 1, X);
			ShowRow(Tile, -Y + 1, Y - 1, -X);
		}

		--X;

		RadiusError += 2 * (Y - X + 1);
	}
}

}

void AFowActor::ShowRow(FIntPoint& Tile, const int32 StartX, const int32 EndX, const int32 Y)
{
// translate to tile location
const int32 sx = StartX + Tile.X;
const int32 ex = EndX + Tile.X;
const int32 row = Y + Tile.Y;

for (int32 x = sx; x &lt; ex; ++x)
{
	const int32 index = x + row * TextureSize;
	if (index &gt; -1 && index &lt; TextureSize * TextureSize)
	{
		if(!UnfoggedData[index])
		{
			UnfoggedData[index] = true;
			// PixelArray[index] = FColor((uint8)255, (uint8)255, (uint8)255, (uint8)255);
			// LastPixelArray[index] = FColor((uint8)100, (uint8)100, (uint8)100, (uint8)255);
		}
	}
}

}

Hi guys! We used this awesome plugin for recent UE4 GameJam so here is link 4.15.3 version:

Wow that is really cool. Any chance someone could update it for 4.19 (currently)? I’ll have to take a look at it and see if I can do it myself, but just wanted to ask. Also, is there a way to smooth out the edges of the fog of war circle area around a unit, so that it looks less pixelated? I’m still searching for a decent Fog of War system that works, and so far all the ones on the marketplace use sudo-hacks for their fog of war. For instance, in the RTS toolkit asset, the author used the decal system, which colors the visible area with a decal, but does not allow you to actually see the terrain textures properly beneath the decal. There still seems to be NO well-refined “AAA” fog of war asset out there.

Can somebody upload the project so I can download it and play with it?

how to slove Z plane problem ? there are many three-floors house in our game:(:frowning:

how to slove Z plane problem ? there are many three-floors house in our game:(:frowning:

Here is an update for the fork I made, now working in 4.21Download Here

Hey guys, ive implemented this Fog of War system following the advice and tips on this topic, i wanted to use this on a mobile project for my group.

https://forums.unrealengine.com/filedata/fetch?filedataid=156091&type=thumb

(Shader Model 5 preview)

I managed to launch the project on Android without any kind of Errors/Warnings, but it seems that the Post Process part is not working properly.

https://forums.unrealengine.com/filedata/fetch?filedataid=156092&type=thumb

(ES2 preview, same behaviour on my Android device)

Seeing this i tried to change the Editor Settings in: Setting->Preview Rendering Level-> Mobile/HTML5 -> Android Preview and the behaviour is the same.
Is it possible that i need to change some settings or configuration in “PP_Fow_Mat” in order to have it working properly on mobile devices?

Can anyone tell me what are we standing on in here right now? The first post is written in quite the unreadable format. There are some code pieces and some blueprint photos but where do I even being. I’ve downloaded some FOWFork project and it seems like it works on a basic level but I have no idea where to look for if I want to increase the radius or basically do anything with it.

It’s 11 pages long now and bare with me, but it’s pretty confusing.

Ok, I found some of the settings in FOW Manager class. If I understand correctly, all this does is create a texture and update it on another thread, then sorta covers the world with that texture? So it won’t hide actors that are supposed to be out of sight?

#learn2code :stuck_out_tongue:

How can I achieve an effect like given in the picture?

Can someone upload a ready project? I can’t start a project that uploaded Juancahf (problems with build), Thanks!