Search Unity

Question Surface Shader with Custom Lighting Function Doesn't Receive Shadows

Discussion in 'Shaders' started by CThayer, Apr 16, 2021.

  1. CThayer

    CThayer

    Joined:
    Oct 21, 2018
    Posts:
    7
    Hello Everyone,

    I have been working on a surface shader with a custom lighting function but I'm fairly new to writing complex shaders so I am really stuck on a few things. In particular, I can't seem to get the shader to receive shadows correctly and I have tried everything that I found via Google but nothing has worked. A couple notes first:

    1. I am using a custom lighting function.
    2. I am using a custom SurfaceOutput struct but it contains all of the standard SurfaceOutput struct fields. I just added a few new ones that I needed.
    2. I have included: #pragma surface surf Diffraction fullforwardshadows
    (where Diffraction corresponds to the LightingDiffraction() function)
    3. I have also tried including addshadow on that line
    4. I have tried using the tags:
    "LightMode" = "ForwardAdd" and "LightMode" = "ForwardBase"

    But, so far, no luck. Is there something that I have to call in my lighting function to get the shadows to work? Or is there something else entirely that I am missing?

    I didn't include all of my code because it is kind of long and a bit of a mess at the moment due to it being very much a WIP. However, I totally understand that you might need to see it to be able to help, so I can post snippets or the whole thing if that is actually helpful.

    Thanks!
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    Can you post it here in the forums? Or preferably the entire shader?

    fullforwardshadows
    only enables shadow receiving for point lights, assuming your custom lighting function works with shadows to begin with.

    Adds a generated shadow caster pass. Usually not needed.

    Those are for specific shader passes, which a Surface Shader generates automatically. Those tags don't have any effect when used at the
    SubShader
    level, and are overridden by the generated passes anyway.

    Random thoughts that may or may not be useful:
    There are a handful of different forms of the custom lighting function, not all of which are well documented. If you're using the form that takes a
    UnityGI gi
    input, the shadows are already baked into the
    gi.light.color
    value. If you're using the form that takes a
    half atten
    , then
    atten
    is the shadow. If you're not using those values, you won't get shadows.

    If your shader is transparent, like if you're using
    "Queue"="Transparent"
    or your
    #pragma surface
    line includes
    alpha
    , then shadows won't work at all. Unity's built in renderer doesn't support shadow receiving on transparent objects. There are some work arounds for a single directional light, but it's impossible to support receiving shadows from the built in point or spot lights when you have a transparent object shader.
     
  3. CThayer

    CThayer

    Joined:
    Oct 21, 2018
    Posts:
    7
    @bgolus Thanks for getting back to me! This was really helpful.

    I am using the custom lighting function that takes the UnityGI struct as a parameter but I didn't know that was where the shadow value was encoded. I just tried applying it to my calculated color with a simple multiplication and it seems like it works well for point lights but something is wrong with my directional lights. You can see the difference in the screenshots. It seems like I might just have some sort of issue with the directional light in general, though. The directional light doesn't seem to be creating correct shadows for anything in the scene, so I'm investigating that now.

    One other question:
    Do you know where I can find any info about using the GI data for manually calculating shadows (or how it is encoded)?

    Thanks for the help!
     

    Attached Files:

  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    There's no documentation on it if that's what you're asking. Really the only thing you can do is look at the generated shader code, and then through the shader source code yourself to try and make sense of it all. There's a link to the source pinned at the top of this sub-forum, or a copy of the latest stable version is usually uploaded here by a community member:
    https://github.com/TwoTailsGames/Unity-Built-in-Shaders
     
  5. CThayer

    CThayer

    Joined:
    Oct 21, 2018
    Posts:
    7
    Ok, cool. I had a feeling that this was the type of thing that just isn't documented but I figured I would ask anyway. I have been using the built-in shader source code to try to fill in the gaps in Unity's documentation on shaders, but there are definitely some details that are hard to figure out. (i.e. the shadow encoding).

    Thanks again for the help!
     
  6. tatoforever

    tatoforever

    Joined:
    Apr 16, 2009
    Posts:
    4,368
    If you add addshadow fullforwardshadows decal:blend to your surface shader pragma, your transparent shader will receive shadows. Here's a fur shader with 10 alpha blended pases, all receiving shadows:
    upload_2023-8-6_1-53-7.png
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    This works as long as it doesn’t need to appear in front of the skybox, or another transparent object. In both cases, the skybox and other transparencies in the scene will render on top anywhere an opaque object isn’t already rendered.
     
    tatoforever likes this.
  8. tatoforever

    tatoforever

    Joined:
    Apr 16, 2009
    Posts:
    4,368
    Yeah. It's not a bullet proof solution but with some renderingqueue tweaking might work just fine. A better solution is to decode shadows manually but still won't work with screenspace shadows pass (sice it decodes shadows using depth) unless there's a depth pass (or something that writes to depth) before the transparent pass with the same mesh on the same spot.