Efficient RTS "fog of war" setup.

Blitz3D Forums/Blitz3D Programming/Efficient RTS "fog of war" setup.

poopla(Posted 2003) [#1]
I for the life of me can't figure out how to do an efficient fog of war effect. I would rather not kill the speed of my application by using up the fill rate with alot of transperancy.


Codemonger(Posted 2003) [#2]
Ok this might sound stupid, because I haven't really thought it through, but ...if you create camera fog and disable fog on the ground or entities using the entityfx command, so fog does not affect them for the areas that you can see... ?


RifRaf(Posted 2003) [#3]
You could place large mesh over the map with many vertices and quades in it like a grid over your map when the guy/unit picks up you remove the face of the fog mesh where he picked. Now the cam will only see through where your guys have been..

To make it war craft style.. You could start the fog mesh at an alpha of like .8 you can still see through a little, to keep from seeing the enemy units they too would pick up, and if they hit the fog layer they alpha to 0, otherwise alpha to normal.


RexRhino(Posted 2003) [#4]
Dev, I would use a very simple method:

Split the game board up into a grid, and only allow the camera into areas on the grid where your units have explored. It is fast, easy to implement, and it seems natural.


octothorpe(Posted 2003) [#5]
Here are a couple ideas:

A second set of map tiles and building graphics which are darkened. You could have your program automatically generate these, or automatically generate them if your source artwork has been modified. To make it look really great you could generate gradient versions of each of these tiles to make the map "blend" between visible areas and your fog-of-war, but that might be a little memory intensive!

Alternately, draw a dithered fog-of-war on top of your map instead of a transparent one. Should be much faster than translucency. (e.g. transparent pixel, black pixel, transparent pixel, black pixel, etc.)


poopla(Posted 2003) [#6]
Becuase of the fact that the camera has variable height, and rotational positions, I will most likely implement an entity fading and camera fogging combination. Im so used to traditional isometric RTSs that I threw this method out the window first thing :). Thanks for the suggestions.


RifRaf(Posted 2003) [#7]
copy this code to get a crude idea of what I meant above.
sorry but I dont know how to color the code below green for easy viewing.



removed.. not effective for large number of units


RifRaf(Posted 2003) [#8]
The code above is very slow with many units.. Here is a new fog of war method, using Psuedo grid, and type structure that flags everything visable or not. Here it is.
NOTE:

I was able to make 500 enemies without any real noticable
slowdowns on my machine.. P4 2.4GHZ GeforceTI4200.
Could someone else with a lower spec machine test it out?

EDIT: I updated code with Banks, and it moves 2x fast. 1000 enemies moving around going in and out of fog of war. I now have it set so that the instant they are out of a "players units" area they fade into fog of war even if the area of terrain has been explored. All done via phsuedo map and banks.. No b3d collision or distance checking done.

Ill post more code if anyone is interested.


;the Psuedo Grid (500,500) is equal to real world 0,0
;VALUES if =0 then invisable area, =1 then visbale
Dim mapgrid(1000,1000)
;This is how large each grid square will be in real XZ world values, play with this to see how it works
Global gridindex=20

;tree type
Type tree
Field entity
Field woodleft
Field Visable
End Type


;all units have these properties
Type Unit
Field Friendly
Field Visable
Field Entity
End Type



Graphics3D 640,480

;create friendly unit
U.unit=New unit
u\friendly=True
u\visable=True
u\entity=CreateCube()
EntityColor u\entity,0,0,200
PositionEntity u\entity,Rand(-20,20),0,Rand(-20,20)

;create a few enemies
For i=1 To 5
U.unit=New unit
u\friendly=False
u\visable=False
u\entity=CreateCube()
EntityColor u\entity,200,0,0
PositionEntity u\entity,Rand(-35,35),0,Rand(-35,35)
Next



;put some ground underneath it all
ground=CreatePlane()
EntityColor ground,0,100,0


For I=1 To 100
t.tree=New tree
T\entity=CreateCone()
PositionEntity t\entity,Rand(-100,100),0,Rand(-100,100)
EntityAlpha t\entity,.2
EntityColor t\entity,0,200,0
ScaleEntity t\entity,4,4,4
Next

;our camera
camera=CreateCamera()
temp=CreatePivot()
PositionEntity camera,10,40,40
PointEntity camera,temp
FreeEntity temp
CameraFogMode camera,1
CameraFogColor camera,100,100,100
CameraFogRange camera,25,190

;main loop
While Not KeyDown(1)
For u.unit=Each unit
checkgridarea(u)
;if unit is friendly we change grid he is in to
;visable, if unit is enemy we just check to see if he is
;inside of a visable area or invisable area, in in visable
;we change his alpha and visable state.
If u\friendly=True Then
MoveEntity u\entity,0,0,.1
TurnEntity u\entity,0,-.35,0
Else
MoveEntity u\entity,0,0,-.1
TurnEntity u\entity,0,.35,0
EndIf
Next
RenderWorld()
UpdateWorld()
Flip
Wend


Function CheckGridArea(cu.unit)
entity=cu\entity
Px=EntityX(entity,1)
Pz=EntityZ(entity,1)
gridX=Int((px/gridindex))+500
gridZ=Int((pz/gridindex))+500
If cu\friendly=True Then
If MapGrid(Gridx,Gridz)=0 Then
mapgrid(gridx,gridz)=1
;tree check not neccessary in a rts game as
;you cn usually see the terrain. You could get
;by with only unit checks. wich are fast.
For t.tree=Each tree
If t\visable=0 Then
If EntityDistance(t\entity,entity)<=GridIndex Then
t\visable=1
EntityAlpha t\entity,1
EndIf
EndIf
Next
EndIf
Else
;enemy/unfriendly unit check.. does not reveal map
;only reveals unit if map area is already explored
If mapgrid(gridx,gridz)=1 Then
cu\visable=1
EntityAlpha cu\entity,1
Else
cu\visable=0
EntityAlpha cu\entity,.1
EndIf
EndIf
End Function


SabataRH(Posted 2003) [#9]
If you are wanting fog of war for a 3d-setup then i might suggest something i pulled off awhile back..

Using camera fog (black).
Place entity boxes (markers) like a grid around the map.
As the player approaches these boxes turn their flag on.

Have the game engine determine how heavy the fog should be around the camera based off the entity box flags positioned around the area..

Of course this is just a quick explanation and the calcs behind it go much deeper.. but in theory it worked fine for me and my 3d-rts.

good luck!


Tranz(Posted 2003) [#10]
RifRaf> "I'll post more code if anyone is interested"

I'm interested...I'd like to see your updated code.


RifRaf(Posted 2003) [#11]
Forgive the lengthly code, its mostly remarks




;the Psuedo Grid (500,500) is equal to real world 0,0
;if =0 then invisable area, =1 then visable
Dim mapgrid(1000,1000)

;This is how large each grid square will be in real XZ world values
;meaning our virtual grid squares are 20x20 on x+z axi in 3d space
Global gridindex=20

;globals required for the BANK functions
;all of our checks will be at an offset of 500
;this is because our bank array cannot go into negative numbers
;using 500 offset makes 500 equal to 0,0 of real 3d space.. now 0,0
;of our grid is equal to -500*gridindex,-500*gridindex of real 3d XZ space
Global MapBank,CleanBank
mapbank=makebank(1000,1000)
CleanBank=makebank(1000,1000)


;how often we will zero out the vitual grid
Global DetailFogtimer#=MilliSecs()+100


;tree type
Type tree
Field entity
Field woodleft
Field Visable
End Type


;all units have these properties
Type Unit
Field Friendly
Field Visable
Field Entity
End Type



Graphics3D 640,480
;our camera
camera=CreateCamera()
temp=CreatePivot()
PositionEntity camera,10,60,-40
PointEntity camera,temp
FreeEntity temp
CameraFogMode camera,1
CameraFogColor camera,100,100,100
CameraFogRange camera,5,110

;create friendly unit
U.unit=New unit
u\friendly=True
u\visable=True
EntityParent camera,u\entity
u\entity=CreateCube()
EntityColor u\entity,0,0,200
PositionEntity u\entity,Rand(-20,20),0,Rand(-20,20)

;create a few enemies
For i=1 To 200
U.unit=New unit
u\friendly=False
u\visable=False

u\entity=CreateCube()
EntityColor u\entity,200,0,0
PositionEntity u\entity,Rand(-35,35),0,Rand(-35,35)
Next



;put some ground underneath it all
ground=CreatePlane()
EntityColor ground,0,100,0


For I=1 To 100
t.tree=New tree
T\entity=CreateCone()
PositionEntity t\entity,Rand(-100,100),0,Rand(-100,100)
EntityAlpha t\entity,.3
EntityColor t\entity,0,200,0
ScaleEntity t\entity,14,14,14
Next

;main loop
While Not KeyDown(1)
If MilliSecs()>detailfogtimer# Then
detailfogtimer#=MilliSecs()+200
detailfog()
EndIf

moving#=0
turn#=0
If KeyDown(200) Then Moving#=.3
If KeyDown(203) Then turn#=-2
If KeyDown(205) Then turn#=2
For u.unit=Each unit
checkgridarea(u)
;if unit is friendly we change grid he is in to
;visable, if unit is enemy we just check to see if he is
;inside of a visable area or invisable area, in in visable
;we change his alpha and visable state.
If u\friendly=True Then
MoveEntity u\entity,0,0,moving
TurnEntity u\entity,0,turn,0
Else
MoveEntity u\entity,0,0,-.1
TurnEntity u\entity,0,.35,0
EndIf
Next
RenderWorld()
UpdateWorld()
Flip
Wend


Function CheckGridArea(cu.unit)
entity=cu\entity
Px=EntityX(entity,1)
Pz=EntityZ(entity,1)
gridX=Int((px/gridindex))+500
gridZ=Int((pz/gridindex))+500
If cu\friendly=True Then
If Getbank(Mapbank,Gridx,Gridz,4000)=0 Then
Putbank(Mapbank,gridx,gridz,4000,1)
;tree check not neccessary in an rts game as
;you cn usually see the terrain. You could get
;by with only unit checks. wich are fast.
For t.tree=Each tree
If t\visable=0 Then
If EntityDistance(t\entity,entity)<=GridIndex Then
t\visable=1
EntityAlpha t\entity,1
EndIf
EndIf
Next
EndIf
Else
;enemy/unfriendly unit check.. does not reveal map
;only reveals unit if map area is already explored
If Getbank(mapbank,gridx,gridz,4000)=1 Then
cu\visable=1
EntityAlpha cu\entity,1
Else
cu\visable=0
EntityAlpha cu\entity,0
EndIf
EndIf
End Function





Function detailfog()
;this function will set the whole grid back to 0
;meaning unexplored. Terrain should have a way
;to stay visable.. here is how I did it. When terrain
;is in sight, its alpha is chaged from a low number to 1
;this will change it to visable regardless of the grid value
;units are different, they always check grid value to see
;if they should be visable. So when a friendly unit is not
;nearby they are not visable.
CopyBank cleanbank,1,mapbank,1,4000000
;if you remove the call to this function. Enemy units will
;remain visable in areas the player has been, even if player
;is no longer there
End Function

Function MakeBank(Xlen,Ylen)
;makes a bank with the 2 dimensions you specify
Mybank=CreateBank((xlen*4)*(ylen*4))
Return Mybank
End Function

Function GetBank(Bank,Xindex,Yindex,AXlen)
;will return the value in the bank. Lets you use it
;like a 2 dimensional array though. AXLEN is the first
;arrays max length.. so in b=CREATEBANK(10,20)
;you would call Getbank(b,x,y,10)
Return PeekInt(bank,((Yindex-1)*(AXlen)+((Xindex-1)*4)-1))
End Function

Function PutBank(Bank,Xindex,Yindex,AXlen,VALUE)
;same as getbank but you insert a value
PokeInt(bank,((Yindex-1)*(AXlen)+((Xindex-1)*4)-1),value)
End Function


Tranz(Posted 2003) [#12]
wow!

That is much faster!

cool stuff!


RifRaf(Posted 2003) [#13]
Thanks. Are you doing an rts? if so I have some models I made that you can have for RPG style.


poopla(Posted 2003) [#14]
We are working on an RTS, but the art is all being done by the team artist to keep legal problems to a minimum. Thanks for the offer though dude!!


Pepsi(Posted 2003) [#15]
Hi Dev,

I've been thinking for awhile about traditional isometric RTS's on how to do 3D fog of war like that. I dunno if you have found a final solution to what you asked for yet or not, but this is my theory I will approach in which I havn't tested via code... yet.

For a 3D RTS that only pans the camera view with no view rotation what so ever, this method would use some type of fog of war layer configuration over the terrain itself.

The Fog would actaully be setup as a single surface mesh built with enough evenly spaced small polys. This fog mesh will have a single dark color to it and also have EntityOrder to set it to display in front of the terrain. Yes, the Z-Order is out the window for it. The fog of war is usually above everything else on the terrain anyways.

Now, we need an algorithm to match your unit's position on the x/z plane to an array that points to a vertex index of the Fog mesh. So basically here, we want to know exactly the vertex index closest to the center of your unit at all times. Then we alpha the vertex to 0 and then the Fog of War Mesh opens up to let you see your unit and the terrain around it.

Ofcoarse we want more than one vertex to be alpha'd down. My suggestion here is to use some kind of circular array'd pattern to instantly make the Fog of War area around your unit disappear. This pattern can be made to fit a "view range" from the center of your unit. Ofcoarse we want to have an old copy of the pattern to fill in the old fog of war area when the unit is moving. This circular pattern can have various alpha values to make the edges of this circular view range to seem to fade into the dark fog. Also, when a unit view range area merges in with another unit there shouldn't be any problems with various alpha values between the two. Just keep the highest alpha value of the two patterns by comparison( I get that right?).

Thinking more into it, the Fog mesh would probably be more efficient if split up into 9 same sized meshes in which a section is a bit bigger then the size of the current playfield resolution. With that, you can do something similuar as a scrolling 2d tiling effect. This can help to eliminate the "bigger the map the more polys used" problem I see in using only one fog mesh for the whole map. Obviously, coding that is a bit more envolved, but should be more awarding in certain situations.

One thing that eludes me at the moment is thinking how I would approach the algorithm to get the closest vertex of the fog mesh to the center of your unit. Looking directly down on the terrain is easy to calculate, but when you have the iso view from an angle, the alogirthm needs to shift the unit's position in order to get the 'view area' of the unit to be centered with it( I guess a simple tweak of the unit position will do it). Otherwise, we'll definitly get an uncentered circular area in the fog.

---------

Just thought I'd throw this idea out at you or any one else just in case if you are still looking. It will be awhile until I get to program this up. I really like the idea of using the vertex alpha capability this way. Should be able to make some smooth looking effects( ie: mabie different colored fog, the circular area could breath in and out a bit, the circular area doesn't have to be completly circular as in it could have a puffy looking pattern look, unit gets killed then the fog smoothly swallows up the dead unit's viewing area, rotating pattern to only show the field of view, etc...).

talk ta ye laters...