# Isometric smooth fog

I'm working on a simple 2d game with direct3d 9. It's a isometric game with diamond tiles and a staggered map. This is what I have:

As you see I have some kind of fog which is acomplished by having a fog matrix which is true (clear terrain) or false (obscure terran). But the result is very chunky. The fog moves as the player moves by tiles but not by pixels. Basically I check for every tile if there is fog, if so I just change the color of that tile:

D3DCOLOR tile_color = 0xffffffff;
if(scene->fog[i+mapx][j+mapy] == FOG_NONE) { tile_color = 0x666666FF; }
g_pSprite->Draw(texTilesNew,&rect,NULL, &D3DXVECTOR3(pantx,panty,0.0f), tile_color);


Where parameter tile_color is:

A Color structure. The color and alpha channels are modulated by this value. The Transparent value maintains the original source color and alpha data.

I also would like the fog to be smoother, for that I followed this "tutorial" but I haven't managed to work it it out becuase I think the tutorial implements a diferent kind of fog than I am.

http://www.appsizematters.com/2010/07/how-to-implement-a-fog-of-war-part-2-smooth/

• How about more levels of fog instead of just on-off, depending on the distance? IMO, the tiling gives some kind of retro effect which may be positive for your specific game. – Panda Pajama Dec 18 '12 at 9:30
• Do you want smooth edges? – bandrewk Dec 18 '12 at 10:47
• I've already thought about instead of on or off tile, add some levels. But the thing is, the player moves smoothly by pixel, the map "camera" also moves by pixel. So for example, if the player moves 5 pixels, the fog should also move only 5 pixels and not wait until it moves a complete tile. – marcg11 Dec 18 '12 at 10:52
• Okay, so how about overlaying a semitransparent dark image with a fully transparent hole in the center over the whole screen? – Panda Pajama Dec 18 '12 at 11:36
• @PandaPajama , the thing is that the visible area is not centered and constant, it moves depending on the character's direction. Besides, there has to be a way that doesn't involve adding images to do the trick. – marcg11 Dec 19 '12 at 8:49

All right, the question has become much more sophisticated, so I'll upgrade my comment to an answer.

There are lots of ways to do what you want to do. The more precise you want your lighting calculations, the more complex the program will be, so I'd advice you focus on keeping it simple, and dedicate more of your time to making the game fun instead of getting stuck with technical details.

But anyways, here are some methods I can think of to accomplish what you want:

1. Do the lighting as a post processing effect! You won't believe how common these simple approaches are used in AAA games. Add a black sprite spanning the entire game area, with a transparent hole in the middle. PNG and DXT support 8-bit alphas, so you can make it as smooth as you want. The main disadvantage is that the shape of the shadow is mostly static. You can do some interesting tricks by messing with the perspective matrix, but is hardly optimal.

2. If you can calculate the lighting separately for each tile, multiply the sprite color by the level of shadow at each tile, or overlay a black tile with the alpha value set to the level of shadow for each tile. The main disadvantage is that if the tiles are too large, or if the shadow range is too small, you will easily notice the variation between tiles. This is by the way, what they did in many Ultima games.

3. Instead of calculating lighting for each tile, calculate it for the borders, and let the graphics engine interpolate the lighting across each tile. To do this, set the color for each vertex of your sprite mesh, and set SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD). The main problem with this solution arises with very bright lights with very short propagations. You may notice some artefacts near the center.

4. A much more complex solution would be to calculate lighting per pixel. To do this, you can set the position of your player as constants to your pixel shader, where you perform the lighting calculation. This will be precise to the pixel level, but requires you to change your graphics pipeline to the programmable one (in case you're using the fixed pipeline). This is relatively complex. The main problem with this solution (and all the other ones above) is that they don't concern sub-tile shadows. In which case...

5. You can also implement the lighting manually. This is really complex and not for the faint of heart, but also very fun. There are tons of approaches to do this, so you can start asking Prof. Google something along the lines of "2d dynamic lighting".

• So it's not a straight-forward solution... – marcg11 Dec 19 '12 at 9:58
• How straightforward would you like your solution to be? The more complex you want your answer to be, the more complex the implementation will be. – Panda Pajama Dec 19 '12 at 10:04
• Well, the thing is that I'm no expert in direct3d, I've just started programming with this api some weeks ago. But I guess there isn't a way of accomplishing that (besides point nº 1) without being an expert of the matter. – marcg11 Dec 19 '12 at 10:17
• I don't know what your g_pSprite looks like, but if it is simply two triangles drawn with 2D perspective, you can easily implement option number 3 by setting different colors for each vertex. But if you're a beginner, maybe Direct3D is too overwhelming. Why don't you try a simpler engine so you can understand all the details of a graphics pipeline before diving into Direct3D, which one may think was deliberately made unnecessarily difficult to use. A simple question: did you write this program? or are you copying some kind of sample code. – Panda Pajama Dec 19 '12 at 10:23
• g_pSprite is of type LPD3DXSPRITE . The load sprite method i just do D3DXCreateSprite( g_pD3DDevice, &g_pSprite );And then load all necessary textures with D3DXCreateTextureFromFileEx. I presume it's all quads, but I'm not sure. And yes, it's my program. – marcg11 Dec 19 '12 at 11:51

Here is a simple proposal: you could try modulate the fog intensity for each cell. Here is an example of applying a simple convolution filter:

float fog = 0.0;
for (int dj = -3; dj <= 3; dj++)
for (int di = -3; di <= 3; di++)
if (scene->fog[i+di+mapx][j+dj+mapy] == FOG_NONE)
fog += 0.0903142 / (0.5 + di * di + dj * dj);
if (fog > 0.0)
tile_color = (int)(0xff - 0x99 * fog) * 0x01010100 + 0x000000FF;

• This perfectly works but the gradient is between tiles and not between pixels ina single tile. – marcg11 Dec 18 '12 at 13:02
• @marcg11 can you maybe show how you render tiles? I can see you have a tile_color, but how does it really affect the rendering? – sam hocevar Dec 18 '12 at 13:38
• I've edited the original post for the code. I just draw the tile and the tile_color is like a tweak to colorize... – marcg11 Dec 19 '12 at 8:51
• @marcg11 Thanks. Any chance to get a look at the Draw method then? – sam hocevar Dec 19 '12 at 11:21
• link – marcg11 Dec 19 '12 at 11:44

Instead of storing booleans in your fog matrix, you could store floating-point values. This would represent the amount of fog on each tile, between 0 and 1. Then simply blend your color depending on the tile's amount of fog:

float fog_amount = scene->fog[i+mapx][j+mapy];
tile_color = tile_color * (1.0f - fog_amount) + 0x666666FF * fog_amount;


There are probably several ways to generate this fog matrix, but one way I can think of is:

• Create your matrix as you do now (with true = no fog = 0.0, and false = full fog = 1.0),
• And apply a bit of gaussian blur on it.

EDIT

I'm not sure that will be necessary (this is simply an artistic choice) but if you want the fog amount to change directly with the player's moves, you'll have to generate this fog matrix using directly distances from the player. E.g. if you want a simple fog circle, that's what you could do for one tile at (i,j) in your fog matrix:

float distance_to_player = distance(tile_pos[i][j], player_pos);
fog[i][j] = (distance_to_player - FOG_START) / (FOG_END - FOG_START);


EDIT 2

That's if you want to keep a "tiled" fog. Overlaying a translucent image as suggested by Panda Pajama in his comments might be a much simpler solution, but it will give you a different result. Once again, this is an artistic choice you have to make.

• But what about the fog moving as the player moves, by pixel and not by tile? It's pretty much the same result as the answer below. – marcg11 Dec 18 '12 at 13:19
• "0x666666FF * fog_amount"? What is that "0x666666FF"? – API-Beast Dec 18 '12 at 14:35
• @Mr.Beast That's the fog color, as in the OP – Laurent Couvidou Dec 18 '12 at 17:55
• @marcg11 Yes that's equivalent to Sam Hocevar's answer. He's just giving you the code to do the Gaussian blur directly per-pixel. – Laurent Couvidou Dec 18 '12 at 17:59
• @marcg11 Edited for taking player moves into account. – Laurent Couvidou Dec 18 '12 at 18:15