Search Unity

How can I control fog color based on skybox color?

Discussion in 'General Graphics' started by Drewson, Mar 18, 2015.

  1. Drewson

    Drewson

    Joined:
    Apr 19, 2009
    Posts:
    168
    Hello - I have a gradient on a skybox, and I want the terminal fog color to be the same as the sky color behind the object that is being occluded. But it still needs to be fog and respect distance.

    I see one way of doing it without actually using fog, with a gradient of my choosing on a skybox. The skybox gets masked out by the depth map, and then overlaid onto the non-sky geometry. You would be able to look down into the depths, and the blackness below gets darker gradually like a "fog" because it is masked by the depth operation. Look up and see the same phenomenon with the lighter color. Basically control "fog" terminal color by camera angle.

    See a mockup below with grey cubes at various distances that I made in photoshop - note how the very distant cubes are getting fogged in a color that blends with the skybox:

    fog_plus_skybox.JPG

    What would be the best way to implement this, and could it be performant on mobile devices?

    Thanks :)
     
    Last edited: Mar 18, 2015
  2. Maxi77

    Maxi77

    Joined:
    Mar 3, 2015
    Posts:
    15
    I have been trying to solve the same problem.
    I am using the procedural skybox in unity 5, and would like the geometry to blend in based on distance from camera. The picture above is a great example.
     
  3. Drewson

    Drewson

    Joined:
    Apr 19, 2009
    Posts:
    168
    Thanks - yeah I'm not a master of rendering, got some shader skills but this stuff is over my head.
     
  4. Drewson

    Drewson

    Joined:
    Apr 19, 2009
    Posts:
    168
    Bumping my question.
     
  5. DragonRider

    DragonRider

    Joined:
    Jul 19, 2012
    Posts:
    11
    If all you need to do is change the fog color based on camera angle, it's fairly simple to script - lighten the fog when facing the sun, darken it when facing away - a rather cheap illusion that can work well in certain situations. But it's far from perfect.

    Using the skybox as render color for the fog is trickier, but certainly doable.

    My theory goes something like this:

    Render the skybox to a buffer.
    Render the depth map.
    Overlay skybox image onto main camera using depthmap as alpha ( would need to apply some maths to determine where fog starts and ends ).

    Far from elegant, but if you can figure out how to implement it, it might do the trick.
     
  6. Recluse

    Recluse

    Joined:
    May 16, 2010
    Posts:
    485
    Nice image! It would be brilliant if Unity's fog would do something like this out of the box, rather than just fading to a single colour. I'm wondering how to get the fog colour to match the constantly changing procedural skybox of a night-day cycle.

    Unity's procedural skybox shader looks lovely as the directional sun light rotates, but the effect is ruined by the global fog, which stands out against the horizon. Can we have a fog in Unity that fades objects out to transparency?
     
    Last edited: May 15, 2015
    gstarch likes this.
  7. Soul-Challenger

    Soul-Challenger

    Joined:
    Dec 30, 2010
    Posts:
    152
  8. Threepwood

    Threepwood

    Joined:
    Jul 23, 2009
    Posts:
    95
    Just looked at KinoFog above. It only works with cubemap skyboxes and not procedural ones.
     
  9. Discord

    Discord

    Joined:
    Mar 19, 2009
    Posts:
    1,008
    KinoFog worked perfectly with a cubemap, I really wish there was something comparable that worked with the procedural ones as well.
     
  10. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,348
    Discord likes this.
  11. Discord

    Discord

    Joined:
    Mar 19, 2009
    Posts:
    1,008
    Thanks for the tip! I was able to get it working by creating another skybox material, passing it the data from a reflection probe, and then passing that material to KinoFog. So a little silly having to use two different skybox materials, but it was a quick fix.
     
  12. jc_lvngstn

    jc_lvngstn

    Joined:
    Jul 19, 2006
    Posts:
    1,508
    So...I've been lurking in the forums for a while. Not active at all like I used to be, but I still love reading various forums. Especially the graphics/shader ones.
    And I just have to give some kudos and appreciation to bgolus. Man...you are incredibly helpful, thanks for sharing your knowledge in these areas, ESPECIALLY shaders. I see post after post where this helps MANY people. You are a huge positive in the Unity community.
     
    UnityLighting likes this.
  13. UnityLighting

    UnityLighting

    Joined:
    Mar 31, 2015
    Posts:
    3,876
    bgolus help me a lot too. He is very helpful man and very clever in shader programing.
     
  14. andrew-lukasik

    andrew-lukasik

    Joined:
    Jan 31, 2013
    Posts:
    249
    I'm definitely not a shader wizard here (more of a noob really) but figured out a way to make a fog color match with skybox colors behind it (procedural too).
    I made a new Camera nearly identical and parented to to Main one. But this one renders ONLY skybox (but I can imagine some custom bg layer with fx meshes here too) to RenderTexture (fairly small in my case). Then after few changes in both GlobalFog.cs and GlobalFog.shader I feeded that RenderTexture as fog color :D



    Steps to follow:

    - import "Legacy Cinematic Image Effects" package https://www.assetstore.unity3d.com/en/#!/content/51515
    EDIT: proper link as suggested in post below: https://www.assetstore.unity3d.com/en/#!/content/83913

    GlobalFog.cs changes:
    - add new field somewhere at the beginning of this class:
    Code (CSharp):
    1. [SerializeField] RenderTexture _fogColorTexture;
    - setup feeding mechanism for render texture to GlobalFog shader
    Code (CSharp):
    1. public override bool CheckResources () {
    2.             /* some code here left unchanged */
    3.  
    4.            //insert code below after line that look like this: "fogMaterial = CheckShaderAndCreateMaterial(..."
    5.             if( _fogColorTexture!=null ) {
    6.                 fogMaterial.SetTexture( "_FogColorTexture" , _fogColorTexture );
    7.             }
    8.  
    9.             /* some code here left unchanged */
    10.         }
    GlobalFog.shader changes:

    - inside "Properties {}" add new line:
    Code (CSharp):
    1. _FogColorTexture ("Base (RGB)", 2D) = "white" {}
    - under "CGINCLUDE" add:
    Code (CSharp):
    1. uniform sampler2D _FogColorTexture;
    - find ComputeFog function and insert this in one the first lines there:
    Code (CSharp):
    1. half4 fogColor = tex2D( _FogColorTexture , UnityStereoTransformScreenSpaceTex(i.uv) );
    - change these lines:
    Code (CSharp):
    1. // Do not fog skybox
    2. if (dpth == _DistanceParams.y)
    3.     fogFac = 1.0;
    to:
    Code (CSharp):
    1. // draw skybox from my RenderTexture
    2. if (dpth == _DistanceParams.y)
    3.     return fogColor;
    - and lastly, replace ending of this function:
    Code (CSharp):
    1. return lerp ( unity_FogColor , sceneColor , fogFac );
    with:
    Code (CSharp):
    1. return lerp ( fogColor , sceneColor , fogFac );
    - create a new Camera nearly identical (same FOV etc) and parented to to your Main one. Set Culling Mask to Nothing and ClearFlags to Skybox

    - in Project window create new RenderTexture

    - set this new RenderTexture as Render Target for our new Camera

    - Add GlobalFog.cs script to MAIN camera and set this new RenderTexture there as Fog Color Texture

    - go to native fog setting in Lighting window, set everything like mode, start/end, density etc - ! BUT ! disable it when done

    - colored fog should be working now

    - in order to achieve perfect match between fog-sky colors (like in my case) you may want to change ClearFlag in your MAIN camera to DepthOnly. But beware that this will effectively draw RenderTexture as sky so setting proper resolution for it will be more important here
     
    Last edited: May 24, 2018
  15. kurt-at-stimulant

    kurt-at-stimulant

    Joined:
    Oct 25, 2017
    Posts:
    1
    Hey Andrew, great post, thanks for this. Totally got it working for me using this method.

    Small correction- you linked to "Legacy Cinematic Image Effects" which doesn't include GlobalFog.cs. The regular "Legacy Image Effects" is here: https://www.assetstore.unity3d.com/en/#!/content/83913
     
    Torbach78 and andrew-lukasik like this.
  16. sfrisby

    sfrisby

    Joined:
    Oct 12, 2014
    Posts:
    1
    Great solution Andrew, thanks for writing that out!
     
  17. andrew-lukasik

    andrew-lukasik

    Joined:
    Jan 31, 2013
    Posts:
    249
    You're welcome! But if you invent or came across any better solution - please let us know!
    I would love to see how can this effect be created in more compact and||or performant way. Or even how more up to date versions of unity can help. For example, will SRP be of any use here?
     
  18. TheUnknown7

    TheUnknown7

    Joined:
    May 13, 2019
    Posts:
    18
    Bumping.

    Please I need this to work with URP
     
  19. Recluse

    Recluse

    Joined:
    May 16, 2010
    Posts:
    485
    I made a custom skybox shader which reads from the depth buffer and then blends over distant geometry to give a foggy appearance. It works even without fog enabled in the scene and only requires one camera. Screenshot (71).png Screenshot (70).png (apologies for the stretched textures - I just dropped these in quickly and scaled taller to make a quick example) :) Skybox also features animating clouds and stars at night.
     
    Last edited: Mar 9, 2022
    andrew-lukasik likes this.
  20. andrew-lukasik

    andrew-lukasik

    Joined:
    Jan 31, 2013
    Posts:
    249
    Oh, that's a great idea. And much simpler one!
    From what I understand this shader must execute for every pixel on the screen, right? Is it a post-process then or something more inventive than that?
     
  21. Recluse

    Recluse

    Joined:
    May 16, 2010
    Posts:
    485
    It's a skybox shader to replace the procedural one that you specify in the lighting / environment tab. The rendering type is transparent and it reads the depth buffer to control the blend alpha, so the sky fades in over distance. I made it in Shaderforge several years ago - unfortunately deprecated now (the SF editor no longer works in Unity 2018 onwards), otherwise I'd share it. I don't know shader language so am working on a new version in Amplify currently. Hopefully share that once it's finished, if anyone would find it useful.
     
    Last edited: Mar 10, 2022
    andrew-lukasik likes this.
  22. Recluse

    Recluse

    Joined:
    May 16, 2010
    Posts:
    485
    Here's a new version, made in Amplify shader editor. Distant scenery fades to invisible nicely (Unity's default fog is disabled in these examples). Screenshot (72).png Screenshot (73).png
     
    NeoTr0nic likes this.
  23. NeoTr0nic

    NeoTr0nic

    Joined:
    May 26, 2017
    Posts:
    1
    This looks amazing! Are you planning to do a tutorial on it or can you share your Shaderforge or Amplify graph?
     
  24. EvansNate

    EvansNate

    Joined:
    Sep 2, 2021
    Posts:
    7
    I think he's using a technique similiar to the Keijiro's KinoFog shader since it's the only one way I can think of to archieve this result.
    You can check it here:
    https://github.com/keijiro/KinoFog

    Said so this only works for Built-In Render Pipeline since on SRP's the OnRenderImage function is not working. In order to make it work you should use a blit ScriptableRenderFeature passing the InverseView projection to the shader you are blitting with. Then you should rewrite the shader with all the URP/HDRP shader libs followig the logic of the KinoFog that isn't super complex.

    Hope it helped!:)
     
  25. Recluse

    Recluse

    Joined:
    May 16, 2010
    Posts:
    485
    Thanks. I will see if I can find the shader (have not been working on this since I first posted).
     
  26. Recluse

    Recluse

    Joined:
    May 16, 2010
    Posts:
    485
    Keijiro's a genius, would have used his effect but I needed various other features so ended up making a shader in Amplify. It's simply a matter of using the depth buffer to control the alpha blending of the skybox shader. No extra scripts or anything needed. I will find and post the shader here, when I can.
     
  27. Recluse

    Recluse

    Joined:
    May 16, 2010
    Posts:
    485
    See sample scene in attached Unity package (built in render pipeline only).
    Fog amount can be tweaked in the skybox material, along with lots of other things.
    Note - camera must render to depth buffer for the shader to work.
     

    Attached Files: