Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to render Volumetric Clouds at a Lower Res?

Discussion in 'Shaders' started by Frostbite23, Jul 4, 2018.

  1. Frostbite23

    Frostbite23

    Joined:
    Mar 8, 2013
    Posts:
    458
    Hello, as you can tell from the title I made an atmospheric scattering shader, companion-ed with some volumetric clouds. Here is proof

    and

    Now with the main clouds being rendered with 64 samples, and for shading there are 8 samples coupled with some noise to reduce "stepping" this makes for some good looking clouds but not feasible for real time performance.

    - (This scene alone with some low res mountains and the sky shader take me down to 60fps - 40fps on a GTX 970, so if you were to put this in a real level with 1000+ meshes and scripts it will wreck havoc).

    So my question is, is it possible to take this skybox material and have it rendered at a lower res? I have no clue where to start and If anyone could give me some pointers or example code I would appreciate it.

    EDIT: To answer some possible questions yall might ask.
    - The whole sky is on a single shader that was originally unity's procedural skybox shader but heavily modified. It is not a post processing shader.
    - No, this is not taking any code or a modified version of kode80's volumetric clouds. This is my own shader.
    - I'm using basically just raw noise for cloud shapes layered a couple of times. Its not running through an fbm/perlin/worley noise function in realtime (which saves alot on performance and allows me to run this at around 60fps with 64 samples) although I should have a lookup texture for that to get more accurate cloud shapes.
     
    Last edited: Jul 4, 2018
  2. brownboot67

    brownboot67

    Joined:
    Jan 5, 2013
    Posts:
    375
    There is a free asset on the store.. Offscreen particle rendering, or something like that, which @jbooth did while we were working on Star Trek Timelines. That'll give you a decent example.
     
    Frostbite23 likes this.
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    That asset is great, but overkill for what you need. That's doing an off screen render of particles (or anything in a specific layer) at a lower resolution then doing a depth aware composite into the full resolution scene as a post process. You don't need to do that depth aware composite assuming your clouds don't intersect with your scene geometry.

    The short version is you need to render out the sky to a render texture that's a lower resolution, then blit that to the screen, or potentially have your skybox shader just draw that render texture. I would do this with a command buffer and key off of the BeforeSkybox camera event.

    Psuedo c# code:
    Code (csharp):
    1. var cb = new CommandBuffer();
    2. cb.name = "low res skybox";
    3.  
    4. // Create render texture identifier named "_Sky"
    5. var rtid = new RenderTextureIdentifier("_Sky");
    6.  
    7. // Create temp render texture at half screen resolution
    8. // (-1 is full res, -2 means half res, -3 is quarter res, etc),
    9. // no depth buffer,
    10. // with bilinear filtering
    11. cb.GetTemporaryRT(rtid, -2, -2, 0, FilterMode.Bilinear);
    12.  
    13. // Set current target to use temp rt
    14. cb.SetRenderTarget(rtid);
    15.  
    16. // Draw clouds into rt
    17. // This should render with the same projection and transform matrices
    18. // the camera has when normally rendering the skybox. I believe during
    19. // this time the camera is treated as if it's at 0,0,0 and only has
    20. // rotation and the normal perspective projection matrix, so rendering
    21. // a cube at 0,0,0 should surround the camera.
    22. cb.DrawMesh(cube, Matrix4x4.identity, skyMaterial);
    23.  
    24. // Set the render texture to be a global texture so it can be accessed
    25. // by the skybox material later. Might not be needed when using a
    26. // named RenderTextureIdentifier?
    27. cb.SetGlobalTexture("_Sky", rtid);
    28.  
    29. // Add command buffer to main camera, or camera of your choosing.
    30. Camera.main.AddCommandBuffer(CameraEvent.BeforeSkybox, cb);


    Then the skybox shader just calculates the screen position UVs and samples the _Sky texture.

    edit: modified for readability
     
    Last edited: Jul 5, 2018
    Frostbite23 likes this.
  4. Frostbite23

    Frostbite23

    Joined:
    Mar 8, 2013
    Posts:
    458
    Wow thank you sooooo much @bgolus !!! I appreciate the help you guys. Finna get this running at fast as possible :)