Efficient RTS "fog of war" setup.
Blitz3D Forums/Blitz3D Programming/Efficient RTS "fog of war" setup.
| ||
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. |
| ||
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... ? |
| ||
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. |
| ||
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. |
| ||
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.) |
| ||
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. |
| ||
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 |
| ||
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 |
| ||
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! |
| ||
RifRaf> "I'll post more code if anyone is interested" I'm interested...I'd like to see your updated code. |
| ||
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 |
| ||
wow! That is much faster! cool stuff! |
| ||
Thanks. Are you doing an rts? if so I have some models I made that you can have for RPG style. |
| ||
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!! |
| ||
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... |