Making Fog-of-War

I’m working on a tile based game and am trying to figure out how to properly display fog-of-war. This image should give you a good idea of what I’m aiming for. So far I’ve tried several different methods, and they’ve all either failed or had serious drawbacks.

  1. Manually edit the texture on tiles using the bge.texture module
    -Failed because tiles of the same type share the texture, so changing the fog on one tile changes the fog on all tiles of the same type

  2. Use UV editing to change the texture
    -Same reason as method 1. Tiles of the same type share UVs, so modifying one changes them all.

  3. Use actions to animate the texture influence
    -Texture actions don’t seem to work in the BGE. Even if they did, this may have the same problem as the previous methods.

  4. Putting a semi transparent plane over each tile with fog.
    -This method actually works pretty well. However, the amount of tiles I’m trying to have on the screen combined with the fact that fog tiles use transparency puts a very heavy load on the rasterizer (jumps from about 10ms without fog to >18ms with fog). While this isn’t absolutely terrible, I would like people to be able to run the game consistently above 60 fps.

There’s one other method I’ve thought of that would probably work, but I don’t like for a couple of reasons:
5. Have two copies of each tile: one with fog and one without
-Tedious to make and seemingly unnecessary to have two of each tile
-I want to be able to fade the fog in and out smoothly. This method wouldn’t allow that.

So I’m kind of at a loss for other ideas right now or ways to fix the ones I currently have. Any help would be greatly appreciated.

two models, one high quality, one low quality / dark ?

That’s solution 5 I mentioned, and these aren’t models, they’re textured planes with one face.

You can do the bright close circle with a simple plane close to the camera: transparent in the middle, opaque near the edge.
Then for the unveiling you can have then default vertex colour to black, but when the player is close (getDistTo) set the vertex colour to white (or no change from texture below).
Actually, object colour would probably be easier, but I haven’t tried playing with that from python yet.

Yeah, use object colour, otherwise the sharing mesh/vertex colour data will cause problems.

Let me see if I understand you correctly. You’re suggesting I use one large plane in front of the camera and subdivide it so that each vertex lines up with a tile below. Then set each vertext to be transparent or opaque depending on if the tile below is revealed or has fog.

While it sounds doable, I have a few concerns:
-The camera moves smoothly (it isn’t locked to the grid), so I can’t just parent the plane to tha camera. It would have to stay still and only move when the camera has moved a full grid length in a certain derection.
-As mention earlier, I have a fairly large number of tiles on the screen (about 1000). This means that every time the fog plane moves I’d have to iterate through 1000 vertices and calculate for each one whether it should be transparent or semi opaque. I’m fairly certain this would cause noticeable and annoying delays.
-While not as bad as having 1000 1-face transparent planes, having one 1000-face transparent plane may still increase the load on the rasterizer in addition to the huge logic cost mentioned above.

While I could mitigate the first two problems with some cleaver programming, I’d rather search for a simpler solution before writing a lot of code that may not be necessary in the end.

What sdfgeoff suggests is a ggod way to do it! But it can get messy if ou need too many tiles! In his case, each tile will e an object(plane)! I’d use this method instead of a vertex color one.
So, forget about transparency and chane the tiles to a darker color when far from the player. Group he tiles in a list so only them are checked for proximity.

What you’ve suggested is method 4. Using object color instead of transparency doesn’t help as it puts just as much strain on the rasterizer (additionally, I also frequently ran into an issue that seemed to be a bug where the planes wouldn’t be transparent).

I can’t edit the object color of the tiles themselves because editing the object color completely removes the texture on the tile.

And yes, adding currently revealed tiles to a list could help, but you’re assuming there’s only one character on the map that reveals fog. There could be many characters around the map, so when jumping quickly to another part of the map or scrolling quickly, I’d still have to check every single fog vertex.

Thanks for the suggestions guys. For now I’ve just decided to go with method 5 since it’s the only one that works while still having good performance. Maybe I’ll find a better way in the future.

Maybe I’m missing something, but why not just have one large plane over the whole map, subdivided so that roughly one vertex is over each tile. Then, use a ray cast downward to get the vertex over a tile, and set its vertex color to be transparent when you want to ‘delete’ the fog on that tile.

That way, you’re only dealing with one instance of the fog of war mesh (rather than one per tile space), so there’s no ‘mesh sharing’ problems, and you only have to change the vertices that will be altered by a unit moving (for example), rather than all of them. Also, once you change the fog of war once, it’ll stay that way for the rest of the match (until you switch scenes).

That would actually work quite nicely, but again my implementation has a few problems with it.

-I’m using GLSL shading. From the testing I did, setting vertex colors works in Multitexture mode but not GLSL.
-I want the fog to strictly remain over a single grid and cover it completely. Setting vertex colors causes there to be a smooth transition between fog covered grids and revealed grids (though this might be a nice feature if the game wasn’t grid based).
-The world wraps around. While doable, I would have to add extra code to re-position the fog plane when the camera goes around the world border.

Setting vertex colours smooths? Nope.
The same physical vertex can have different colours for each face attached to it. You can get hard lines. Just play around in the vertex paint editor and use ‘selected faces only’ to see.
Or just pick one at random in game and change it’s colour.

Indeed!
You can set material color or vertex color in the materials options, it will work on GLSL!
Now using a fog plane above the tiles plane is for me the best idea! You don’t even need to do many calculations. Just add every vertex to a position dict: ((x,y): vertex), and retrieve the player’s position in the map and set to transparent the vertices in the dict at that position. Set to default the ones you just left(which should be in a list).
That will prevent you from having 1000’s of tiles, but just 1 plane with the texture tiled. The fog plane can just cover the entire map.
Maybe an example can help…

A slight revision to my suggestion would be to just make each face in the fog-of-war mesh correspond to a tile, and then work with the mesh faces rather than the vertices.

The rayCast() function can return the hit face. From that, you can get the face’s vertex indices rather easily. So, just have a unit (again, for example) cast a ray straight down into the fog of war plane, get the face, get the vertex indices making the face up, and then loop through those vertices and set the vertex color accordingly, thereby changing the fog of war tile, and not just a single vertex. It should be pretty simple.

Also, Torakunsama’s correct - GLSL mode does accept vertex coloring, you just have to enable it in the material. As for wrapping, why is it necessary to move the fog plane at all?

EDIT: Ah, I see what you were saying. I would just make it so that the fog of war mesh extends slightly beyond the boundaries of the map, so that you don’t see the edge when the camera goes to the other end of the map. Then, code it in to change the fog-of-war one map size away each time the mesh is changed (that way, to the camera, it seems like the fog-of-war mesh is looping).

Then, code it in to change the fog-of-war one map size away each time the mesh is changed (that way, to the camera, it seems like the fog-of-war mesh is looping).

If the world wraps around, here’s no need o move the fog plane at all!
Also it depends if the ame will be 2D or 3D(sorry if I missed tha detail). Solarlune suggestion is as good as mine, dictionary or raycast, as long as you get the face, you can change it’s 4 vertices color/alpha.
I’m making a small example!

Great idea and founder!!!

Maybe I’m missing something, but how about have (one) large plane across the terrain (like clouds) and edit its texture with videoTexture. I think I can remember a thread regarding real time texture painting in resource forum.

If you choose the UV that one pixel matches one tile. It should be straight forward to get a fog-of-war.
And with mip-mapping you get free texture smoothing.

Just a suggestion to think about

Err, before I go coding, I had something in mind earlier, it’s codeless so I stoped coding I quickly made this once I got home…
It’s texture based, but the camera has to stay in one position, if it orbits, you’ll need to adjust the mapping offset!
BLEND

Edit: A second option is to use a spot light, and have a very faint hemisphere light, to make the fog/shadow!

Those suggestions are good, but they wouldn’t work on a per-tile basis. If you were to do the ‘multiply blending mode’ method for the fog, you would actually have to code it in to render the light parts out over a black background, and then draw that texture as a multiply-enabled blending mode over the screen (as I did with Valchion).

I also had an idea, although I can see it has some flaws. Never the less, I thought I’d share it.
Fog, in its usual sense, occludes the view of the camera. Therefore, you would often be able to place fog simulation as a simple 2D texture overlayed on the camera with some faked depth. Fog of war could be simulated similarly. This is complex in some respects:
You could create a texture array with VideoTexture or a Python Array (I think you’d have to define the array using the array module actually). Now, after defing some brush features, you would simple draw the colour onto the texture. You could simple get the depth from the scene pass and use that as the intensity of the fog. I’m not fully sure what this would look like, and it would take more work than I have suggested. If you’re interested, pop up to Martinsh and ask him :slight_smile:
Perhaps I have the wrong defintion. but good to consider anyway. you’d instead want to define points which were occluded and do it that way. then you’d need to use an octree or something for faster searching. The same use of an octree would work for vertex colours of the base mesh.