Search Unity

Differentiating between shadow caster and shadow receiver in 5.2

Discussion in 'Shaders' started by bgolus, Oct 21, 2015.

  1. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Has anyone figured out a clean way (ie: some combination of defines to #ifdef between) to discern between the main directional light shadow depth rendering and the shadow receiver depth rendering? Since 5.0 merged the two it's made it difficult to handle each case differently (useful for screen space alpha test effects and billboard shadow casting).

    The only test I've been able to come up with is to test for an orthographic projection to differentiate between the scene depth and shadow depth, but that only works if the main camera isn't orthographic.

    Code (CSharp):
    1. #ifdef SHADOWS_DEPTH
    2. if (UNITY_MATRIX_P[3][3] == 0.0) // 1.0 for orthographic, 0.0 for perspective
    3. {
    4.   // Is perspective, so rendering camera depth
    5. }
    6. else
    7. {
    8.   // Is orthographic, so rendering directional shadow depth
    9. }
    10. #endif
    Note the use of UNITY_MATRIX_P here, and not unity_CameraProjection which is the current main camera's projection, though unity_OrthoParams.z might work as well.

    I also considered some test between unity_CameraProjection and UNITY_MATRIX_P for equivalence which could differentiate between an orthographic main camera and directional shadows, but it's still ugly as I'd rather avoid the run time branching.
     
    DenisGarshin and Cicaeda like this.
  2. DmitryNovikov

    DmitryNovikov

    Joined:
    May 2, 2015
    Posts:
    6
    Another one ugly way, works with directional light with Normal Bias > 0

    Code (CSharp):
    1. #ifdef SHADOWS_DEPTH
    2. if (unity_LightShadowBias.z != 0.0) {
    3.     // shadow
    4. } else {
    5.     // camera depth
    6. }
    7. #endif
    Unity uses the same shader pass for both shadows and camera depth, so i think where is no right combination of defines
     
    Last edited: Oct 25, 2015
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Hmm, I like that method better than trying to use the projection matrix, but I wonder if there's a value that'll always work regardless of bias settings. Looking at UnityCG.cginc the value you're using is in fact what Unity themselves uses to test between depth camera and directional shadow, though in their case (like in yours) they use the same branch if there's no normal bias. I wonder if there's another value in there that'd be useful. Curiously, unity_LightShadowBias is a float4 but only x y z are used. I wonder if w is set to anything...
     
  4. DmitryNovikov

    DmitryNovikov

    Joined:
    May 2, 2015
    Posts:
    6
    Try to attach command buffers to camera and light (CameraEvent.AfterDepthTexture and LightEvent.AfterShadowMap) and draw your geometry with different shader passes.
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    I think I've found a value that is always different between the depth pass and shadow passes of any kind.

    #ifdef SHADOWS_DEPTH
    if (_LightShadowData.w == 0.0)
    // We're a camera depth pass
    else
    // We're a directional light shadow depth pass
    #else
    // Point or spot shadow depth pass
    #endif


    This value is the distance for directional shadows to fade which is always greater than 0, and is always set to 0 during the depth pass. Interestingly it's also set to something other than zero for all light types.
     
    DmitryNovikov likes this.
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    And it appears this no longer works in 5.3.1p4, the depth camera has _LightShadowData != 0.0 :mad:
     
  7. lunaMGallo

    lunaMGallo

    Joined:
    Jun 29, 2022
    Posts:
    1
    Hey, I'm currently doing it like this:
    Code (CSharp):
    1. #ifdef SHADOWS_DEPTH
    2. if (UNITY_MATRIX_P[0][0] == unity_CameraProjection[0][0] && UNITY_MATRIX_P[0][1] == unity_CameraProjection[0][1] && UNITY_MATRIX_P[0][2] == unity_CameraProjection[0][2]) {
    3.                     v.vertex.xyz += newForward * _ShadowBias;
    4. }
    5. #endif
    But it doesn't look right. I have tried checking all the matrix values but then it deosn't work. I guess I'm just gonna keep using this and hope it keeps working.
    Hope it helps someone ^^
     
    DenisGarshin likes this.