Jump to content
  • Advertisement
Sign in to follow this  
Normalized

Optimizations for projective shadow / fog of war

This topic is 2613 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

[font="Calibri"]I have been working on a fog of war system. Right now, Icreate a texture dynamically then use an orthographic projection. I have it directly sized to the map where 1 pixel equals 1 meter. I pass the texture tothe shader by encoding it only into an alpha channel using an alpha8 texture. [/font]
[font="Calibri"]
its slow right now it's taking 56ms a frame downfrom 420ms but still too high. [/font]

[font="Calibri"]I have attached the code to give you an idea of what I amdoing. Admittedly, I could use a smaller texture and lose the 1 to 1relationship but does anyone have another ideas?[/font]


testfog.jpg

Uploaded with ImageShack.us

[font="Times New Roman"] tags seem broken??/?[/font]

what I do


[font="Times New Roman"][color="#0000ff"][color="#0000ff"]int xLength = myTexture2D.width;[/font][font="Times New Roman"] [color="#0000ff"][color="#0000ff"]int yCounter = 0;[/font][font="Times New Roman"] [color="#0000ff"][color="#0000ff"]int xCounter = 0;
[/font][font="Times New Roman"] [color="#0000ff"][color="#0000ff"]for ([color="#0000ff"][color="#0000ff"]int i = 0; i < colors.Length; ++i)

[/font][font="Times New Roman"] {
colors.a = 0.0F; [color="#008000"][color="#008000"]//clear
[/font][font="Times New Roman"] [color="#0000ff"][color="#0000ff"]if (i / (yCounter + 1) == xLength)

[/font][font="Times New Roman"] {
++yCounter;
xCounter = 0;
}
[color="#0000ff"][color="#0000ff"]else
[color="#0000ff"] [/font][font="Times New Roman"] {
++xCounter;
}
[color="#0000ff"][color="#0000ff"]for ([color="#0000ff"][color="#0000ff"]int i2 = 0; i2 < testArray.Length; ++i2)
[/font][font="Times New Roman"] {

[color="#008000"][color="#008000"]//float luminanceTest = ;//0.299F * colors.r + 0.587F * colors.g + 0.114F * colors.b;[/font][font="Times New Roman"] [color="#0000ff"][color="#0000ff"]if (colors.a < testArray[i2].Luminance)
[/font][font="Times New Roman"] {
[color="#0000ff"][color="#0000ff"]if (testArray[i2].MaxX >= xCounter && testArray[i2].MaxY >= yCounter && testArray[i2].MinX <= xCounter && testArray[i2].MinY <= yCounter)
{
[color="#2b91af"][color="#2b91af"]Vector2 testPos = [color="#0000ff"][color="#0000ff"]new [color="#2b91af"][color="#2b91af"]Vector2(xCounter, yCounter);
[color="#0000ff"][color="#0000ff"]if ((testPos - testArray[i2].Position).sqrMagnitude < ([color="#2b91af"][color="#2b91af"]Mathf.Pow(testArray[i2].Length, 2.0F)) &&
[color="#2b91af"][color="#2b91af"]Vector2.Angle(testArray[i2].ForwardDirection, (testPos - testArray[i2].Position).normalized) <= testArray[i2].ArcLengthDegrees)
[/font][font="Times New Roman"] {
colors.a = testArray[i2].Luminance;
}

}

}

}

}[/font]






and the data I use for each cone

[color="#0000ff"][color="#0000ff"]public [color="#0000ff"][color="#0000ff"]struct [color="#2b91af"][color="#2b91af"]SightTestCase

[color="#2b91af"] {



[color="#0000ff"][color="#0000ff"]public [color="#0000ff"][color="#0000ff"]readonly [color="#0000ff"][color="#0000ff"]float Length;

[color="#0000ff"][color="#0000ff"]public [color="#0000ff"][color="#0000ff"]readonly [color="#0000ff"][color="#0000ff"]float ArcLengthDegrees;

[color="#0000ff"][color="#0000ff"]public [color="#0000ff"][color="#0000ff"]readonly [color="#0000ff"][color="#0000ff"]int MinX;

[color="#0000ff"][color="#0000ff"]public [color="#0000ff"][color="#0000ff"]readonly [color="#0000ff"][color="#0000ff"]int MinY;

[color="#0000ff"][color="#0000ff"]public [color="#0000ff"][color="#0000ff"]readonly [color="#0000ff"][color="#0000ff"]int MaxX;

[color="#0000ff"][color="#0000ff"]public [color="#0000ff"][color="#0000ff"]readonly [color="#0000ff"][color="#0000ff"]int MaxY;

[color="#0000ff"][color="#0000ff"]public [color="#0000ff"][color="#0000ff"]readonly [color="#2b91af"][color="#2b91af"]Color AreaColor;

[color="#0000ff"][color="#0000ff"]public [color="#0000ff"][color="#0000ff"]readonly [color="#0000ff"][color="#0000ff"]float Luminance;

[color="#008000"][color="#008000"]//public readonly float GrayScale;

[color="#008000"] [color="#0000ff"][color="#0000ff"]public [color="#0000ff"][color="#0000ff"]readonly [color="#2b91af"][color="#2b91af"]Vector2 Position;

[color="#0000ff"][color="#0000ff"]public [color="#0000ff"][color="#0000ff"]readonly [color="#2b91af"][color="#2b91af"]Vector2 ForwardDirection;

[color="#0000ff"][color="#0000ff"]public SightTestCase([color="#2b91af"][color="#2b91af"]Vector2 position, [color="#2b91af"][color="#2b91af"]Vector2 forwardDirection, [color="#0000ff"][color="#0000ff"]int minX, [color="#0000ff"][color="#0000ff"]int minY, [color="#0000ff"][color="#0000ff"]int maxX, [color="#0000ff"][color="#0000ff"]int maxY, [color="#2b91af"][color="#2b91af"]Color myColor, [color="#0000ff"][color="#0000ff"]float length, [color="#0000ff"][color="#0000ff"]float arcLengthDegrees)

{



[color="#0000ff"][color="#0000ff"]this.Length = length;

[color="#0000ff"][color="#0000ff"]this.ArcLengthDegrees = arcLengthDegrees;

[color="#0000ff"][color="#0000ff"]this.MinX = minX;

[color="#0000ff"][color="#0000ff"]this.MinY = minY;

[color="#0000ff"][color="#0000ff"]this.MaxX = maxX;

[color="#0000ff"][color="#0000ff"]this.MaxY = maxY;

[color="#0000ff"][color="#0000ff"]this.AreaColor = myColor;

[color="#0000ff"][color="#0000ff"]this.Position = position;

[color="#0000ff"][color="#0000ff"]this.ForwardDirection = forwardDirection;

[color="#0000ff"][color="#0000ff"]this.Luminance = 0.299F * myColor.r + 0.587F * myColor.g + 0.114F * myColor.b - [color="#2b91af"][color="#2b91af"]LinearMath.Epsilon;

[color="#008000"][color="#008000"]//this.GrayScale = myColor.grayscale;

[color="#008000"] }

}

Share this post


Link to post
Share on other sites
Advertisement
A simple solution would be to update only parts of your texture in combination with a double buffer.
Use two alpha textures, the currently displayed and a back-buffer. Then update a 64x64(or whatever) pixel block per frame on the back-buffer (use some kind of PBO or similar), then when the whole map has been uploaded, swap displayed and back-buffer texture and update your fog of war for the next iteration. With the correct balancing of block-size and PBO usage you can update such a map within a few seconds without any real impact on frame rate.

Share this post


Link to post
Share on other sites
[font="Times New Roman"][/font][font="Calibri"]Thanks, that actually sounds kind of elegant. I just hope I donot have too much texture tearing with dynamic units. [/font]

[font="Times New Roman"][/font]

Share this post


Link to post
Share on other sites
Try uploading a very low resolution fog of war masks and then rendering that using a pixel shader. Calculating a huge fog of war texture and uploading it per frame can't be good for performance :)

Share this post


Link to post
Share on other sites

Try uploading a very low resolution fog of war masks and then rendering that using a pixel shader. Calculating a huge fog of war texture and uploading it per frame can't be good for performance :)



Even on a 50 x 50 meter map it still takes 9ms. Most of this time is not uploading but cpu time. On a 200x200 map with 24 cones at least 50 out of 56 ms is cpu time.[font="Calibri"]

for each pixel I test each one of my vision cones

1: See if the cones luminance is greater than the current pixel luminance
[/font]2:[font="Calibri"] Test the vision cone axle aligned bounding box.[/font]
[font="Calibri"]3: Test if pixel really is really inside cone using squared magnitude and angle. [/font]

Share this post


Link to post
Share on other sites
[font="Times New Roman"] [/font]My new plan is to use a render texture and pre calculate the cones texture.

[font="Times New Roman"] [/font]

Share this post


Link to post
Share on other sites
Can't you just render the fog of war using spotlights? The cones equal to the light, and everything is shaded dark unless it is in a cone (cap value for multiple cones could be necessary). Using deferred rendering with hlsl shaders should be quite fast, in combination with a quick check if a cone is on the screen. So this would work gpu side only. If you need the fog of war data on the cpu side (for example : visibility determination of units) you could just calculate the fog of war's boundings at a low resolution..

Share this post


Link to post
Share on other sites

Can't you just render the fog of war using spotlights? The cones equal to the light, and everything is shaded dark unless it is in a cone (cap value for multiple cones could be necessary). Using deferred rendering with hlsl shaders should be quite fast, in combination with a quick check if a cone is on the screen. So this would work gpu side only. If you need the fog of war data on the cpu side (for example : visibility determination of units) you could just calculate the fog of war's boundings at a low resolution..



Not really you r[font="Calibri"]un into the same problem as if you multiple projectors. Namely where the cones over lap area become brighter and brighter the more cones over lap. By rendering to texture, I can have a proper z test. [/font][font="Times New Roman"] [/font]

Share this post


Link to post
Share on other sites
Well you could have a rendertarget texture where you write a 0 to if a pixel has once been lit by a cone, 1 is default. If you use deferred rendering, this texture would simply have the size of the screen. Now on the cones lighting, you read out the value of this texture and multiply it with the lighting component (1 means that a pixel gets lit, 0 means no more lighting). You now clear the texture to 1 once a frame. You get the idea? I don't know if you want to use deferred rendering, but the same idea would work as a postprocessing effect. You could use a red color only float texture as rendertarget, for performance purposes. If I was to make a strategy game I would do it that way.

Share this post


Link to post
Share on other sites

Well you could have a rendertarget texture where you write a 0 to if a pixel has once been lit by a cone, 1 is default. If you use deferred rendering, this texture would simply have the size of the screen. Now on the cones lighting, you read out the value of this texture and multiply it with the lighting component (1 means that a pixel gets lit, 0 means no more lighting). You now clear the texture to 1 once a frame. You get the idea? I don't know if you want to use deferred rendering, but the same idea would work as a postprocessing effect. You could use a red color only float texture as rendertarget, for performance purposes. If I was to make a strategy game I would do it that way.


You can do that if you only want one level and color of fog of war. Bright white and black. Still not sure what you mean by a light ? Like a spot light ?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!