XNA: Adding fog to a LPP (or deferred) pipeline

Hi folks,

After a long delay, here is one more gift for you: how to add fog to your scene. I will talk about global fog, although it can be easily extended to local fog volumes like spheres, cubes, etc.

Fog is a great visual feature in any rendering. It helps not only creating atmosphere and environment cues, but also improves the depth perception of your scene. As a bonus, you can use it to camouflage the unpleasant pop in/out side effect of distant object culling.

Here we have same view with and without fog:

The effect is basically a color interpolation based on the depth of the current pixel. You can have a look here and here for some good tutorials, as I won’t enter the gritty details of the physics behind it (it’s not that hard, though: don’t be scared to learn the real deal).

In the fixed pipeline era, it was really simple to add fog to your scene: just enable a flag, setup two or three parameters and voilà, it’s done. Now, in the programmable age, you should create it by yourself, creating lots of shader permutations (or maybe using dynamic branching) to support the fog formula at the end of the processing.

But hey: what did come to your mind when I said “the depth of the current pixel”? After lots of posts talking about our beloved GBuffer, you should know that we already have the depth buffer as a render target.

With the depth buffer at hand, all you need to do is perform a full-screen pass reading the depth value of each pixel, compute the interpolation formula and alpha blending the fog color.

Sounds easy, heh? Indeed, it is. I’ve implemented both the EXP and EXP2 formulas explained in the links above, just change the fog type to see the difference (check LightPrePass.cs).

Here is a snippet of the shader:


float4 PixelShaderFunctionExp(VertexShaderOutput input) : COLOR0{

float depthValue = tex2D(depthSampler, input.TexCoord).r;
 clip(-depthValue + 0.9999f);

 float mix = saturate((1 - exp( -depthValue * FogDensity )));

 return float4(FogColor.rgb, mix );
}

I'm doing a "clip" to avoid fogging up the skybox or background, where the depth buffer is still the far plane. You can use stencil buffer or another trick if you wish so.

The issue with this approach is that it doesn't work for objects that don't output to the depth buffer, like particle effects and other transparent objects. In this case, you can change those shaders to use the global fog parameters and do the same formula stated above (this is how I'm doing in my personal project).

Anyway, here is the sample source with all the code and assets to play around. Use it at your own risk!!

Ah, by the way, some folks asked me how to add game objects in my framework by code instead of the XML. I put some examples in the initialization of this sample, so take a look if you want.

That is it, see you around!

-J.Coluna

About these ads

About jcoluna

Game developer and musician
This entry was posted in XNA and tagged , , , , . Bookmark the permalink.

23 Responses to XNA: Adding fog to a LPP (or deferred) pipeline

  1. Tiba says:

    Hey mate, Nice work as always!.
    I added Fog to my branch of your LPP framework a while back and i ran in to some problems coz my terrain shader had to many Samplers because i went a lil crazy with multi texture terrain so i do my fog like this:

    shader vars:
    float xFogStart = 2000;
    float xFogEnd = 25000;
    float3 xFogColor; // not in use

    in the VS:
    output.Depth = output.Position.z;
    in the PS:
    float l = saturate((input.Depth-xFogStart)/(xFogEnd-xFogStart));
    return float4(lerp(color,AmbientColor *1.5,l),1);

    Im also working on grass, its comming along very nice.
    Right now im just trying to work out if i want to draw it HW Instanced or put all the grass verts in one buffer and chunk it eg. let cpu build the grass buffers on a different thread and just pass the gpu one big buffer or HW Instanced grass……. both have about the same draw time so idk what to run with

    If anyone wants the code ill be happy to pass it a round, it takes 10-18ms to refreash the grass so i use a 2nd thread and let the main game loop pull vert buffers from the thread(its all synced up nice )

  2. @ JCuluna Nice work – you finally convinced me to move my fog from linear to exp2. Although I actually use a shader parameter for the power, so that the power curve can change at runtime, find it useful for different weather effects.

    @ Tiba – I’d instance it, with nice big chunks of grass together. I don’t think you don’t want small chunks, as too many instances are bad.

  3. Tiba says:

    Hi again, Ok so running with Instanced grass.

    I think my terrain shader is costing way to mush :(

    Here are some SS so you can see the grass and multi-texture terrain:
    http://imageshack.us/photo/my-images/26/forceenge.jpg

  4. Looking nice :) I like the triplanar projection on the cliffs, and the look of the grass and the trees. Are you on Twitter?

  5. Tiba says:

    Hey mate TY very much for the kind words, it still need some work but im very happy with the progress and the SS dont rly do it justist because your missing the dynamic clouds\sky.

    Next thing on the list is volumetric particles with lighting(will be hard as i cant find any info on it for XNA) but thats y i love this!!

    Na mate not on twitter but its something i have been thinking of

  6. I think you should join twitter – other devs like me would enjoy sharing your journey, what you are working on is interesting! It is a great way for us all to communicate, and share ideas like JColuna did with the exponential fog. Add me, and I’ll introduce you to some other devs too :)

  7. jaimo says:

    Thanks a lot. The problem I had was understanding how to put objects in the scene, and now it’s been solved. You’re the best!!! :)

  8. Tiba says:

    here is a video of my work

    • jcoluna says:

      That’s awesome!! Congrats! Do you have it running on xbox too?
      See ya!
      -J.Coluna

    • Looking great! You’ve gotta feel pretty satisfied with this :)

    • Chris says:

      That’s quite nice! Have you tamed your heightmaps yet? I’ve just started to use them in my engine and for reasonably large ones, you really need some quadtree/LOD algorithm to get them to run smoothly.

      • Tiba says:

        Yer mate i have a quad tree…… but i broke it when i did my rewrite because im using a smaller scale the bounding box’s are not in the right place\wrong size so im just brute forceing it atm.

        im using this http://code.google.com/p/billod-xna4/

        i understand most of it as i have had to mkae lots of changes to fin the LPP pipeline but i cant find away to make it any smaller.

        i use to run a scale of 1 for the terrain and it worked well but i had floating point problems because of the land size so i rebuilt it all at a scale of 0.01 for the terrain and now the bounding box’s are the wrong size.

      • Chris says:

        I took a look at that code and tried it out. Pretty effective, but still a lot to dig through. I think it’s using a ROAM algorithm? For me, I think I’ll pass that and use geo mipmapping instead. It looks easier to implement, while still taking advantage of quadtrees. Just a matter of fitting each chunk perfectly in the code.
        But I have to wonder with this approach, would it matter to put all the chunks in one dynamic vertex buffer and update the no. of primitives to draw on each update, or just putting each chunk in its own vertex buffer is good enough.

  9. Gary Ruddock says:

    It looks very, very good. I’d love to achieve something similar, Well done.

  10. RS says:

    Happy new year Mr. Coluna.
    Was messing with the new version and had trouble with something. Kind of silly, but I cannot find where the directional light is for the life of me. I was messing around with the pre-component based version and was used to it being another light to be added. Is there a directional light folded into an environment object or…? : /

    Also, if you don’t mind my asking. Is the ultimate goal of your engine to help with your own game or is the engine being built for its own sake?

  11. Chris says:

    J.Coluna, I really enjoy the work you’ve done so far. I’m making my own custom engine but using some of your ideas to help me along. Have you considered cascaded shadow blending? I have implemented it, showing better results, and an article that talks about it here: http://electronicmeteor.wordpress.com/2013/01/12/done-fixing-the-shadow-maps/.

    Screenshots are old, though. I moved on to Poisson disk sampling which does a fine job for approximating soft shadows. I will probably post shader code later on.

  12. Tiba says:

    @Chris Hey mate i would almost give u my 1st born to see that shader code for the CSM blending.

    I had a look at the guys shader cod ein that link u gae but i cant get my head around it.

    Ps. i should have a new video up in a few days

  13. Tiba says:

    Hello again! here is a new water shader i have been working on

  14. I was very ecstatic to uncover this site on yahoo.I needed to say thank you to you with regard to this fantastic publish!! I surelyloved each little bit of it and I have you bookmarked to look into new stuff you post.

  15. I’ve been browsing on-line greater than 3 hours today, but I by no means uncovered any fascinating post like yours. It’s pretty worth enough for me. In my see, if all webmasters and bloggers produced excellent content material as you in all probability did, the net will probably be a lot more useful than ever before.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s