Search Unity

Is it possible for a volumetric cloud using raymarch to cast shadows?

Discussion in 'Shaders' started by magehuntz, Jul 15, 2019.

  1. magehuntz

    magehuntz

    Joined:
    Mar 24, 2017
    Posts:
    27
    I was studying Ryan Bruck's tutorial on volumetric clouds rendering (https://shaderbits.com/blog/creating-volumetric-ray-marcher), and was trying to recreate it in Unity. I managed to do the 3D texture creation and volumetric rendering with raymarching:


    But as you can see, and as is to be expected, the shadow is cast from the original mesh, and not from the cloud within. I read online that a custom shadow could be created by writing to the depth buffer, but I couldn't find much documentation on how to do that, and I think volumetric clouds would be kind of a special case, since each pixel is checking multiple samples from the volume.

    My question is, would that be possible? I think I'm missing some kind of basic shader knowledge about depth buffers and shadowmaps, so if anybody could show me a starting point to learn those I'd be very grateful!
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    All depth buffers, including shadow maps, can only hold a single depth per pixel (ignoring MSAA, which Unity's built in shadow maps don't use). So for a shadow map, you'd just need to make due with a dithered shadow.

    The way I would probably approach this would be to have either a random value or an index matrix that I get per pixel and use as the cutoff for what density to stop at. Something like a 4x4 index matrix with a 1.0/16.0 to 1.0 range. Then start iterating through the volume. If you reach the requisite density, then write that depth. If you don't reach the requisite density then discard.

    Note: Unity's Standard shader uses a 4x4 index matrix for its semitransparent shadows already, but the pattern is stored in a form that's not useful for this use case. It's a 3D texture which you input in the appropriate alpha value to the volume texture's Z and it spits out the appropriate B&W pattern. You need the full range of values.

    You can write out the depth using out float depth : SV_Depth in the frag function definition. That depth needs to be in the appropriate form, which if you can calculate the view space depth can be converted with this function:
    Code (csharp):
    1. float LinearToDepth(float linearDepth)
    2. {
    3.     return (1.0 - _ZBufferParams.w * linearDepth) / (linearDepth * _ZBufferParams.z);
    4. }
    That will produce a shadow dithered both in the depth and the opacity.
     
    E_Urban likes this.
  3. magehuntz

    magehuntz

    Joined:
    Mar 24, 2017
    Posts:
    27
    Thanks, I'm gonna try that!