oculus-samples / Unity-DepthAPI

Examples of using Depth API for real-time, dynamic occlusions
Other
166 stars 24 forks source link

Combining Shaders #13

Open PG13park opened 7 months ago

PG13park commented 7 months ago

I am not sure how exactly to follow the Implementing Occlusion in custom shaders steps to combine a custom shaders with this one. All my attempts and people I've asked for help have been faliures. I think it would help a lot if there was an example. Here is the shader I am trying to combine it with/add the steps mentioned in part 8 of getting started to. I would appreciate it if you could show me how to add the steps.

What im trying to do is occlude the shadow's drawn on the global mesh by this custom shader. Heres and example photo with the objects and shadows underlined. com DefaultCompany MiniGolfMR-20231123-210251

TudorJude commented 7 months ago

Hey PG13park,

There's a custom shader in the URP Sample of this repository called DepthUnlit.shader. It's under Assets/DepthAPISample/Shaders, you can look at that for reference. It seems to me that you could do something similar to what you see there in your shadow vert and frag functions.

PG13park commented 7 months ago

Thank you for the advice, I just attempted it and it did not work. Do you know what I did wrong? Heres the shader.

ShadowDrawerOcclusion

#

Shader "Custom/ShadowDrawerOcclusion"
{
    Properties
    {
        _Color ("Shadow Color", Color) = (0, 0, 0, 0.6)
    }

    CGINCLUDE

    #include "UnityCG.cginc"
    #include "AutoLight.cginc"
    #include "Packages/com.meta.xr.depthapi/Runtime/BiRP/EnvironmentOcclusionBiRP.cginc"

    struct v2f_shadow {
        float4 pos : SV_POSITION;
        LIGHTING_COORDS(0, 1)
    };

    half4 _Color;

    v2f_shadow vert_shadow(appdata_full v)
    {
        v2f_shadow o;
        o.pos = UnityObjectToClipPos(v.vertex);
        TRANSFER_VERTEX_TO_FRAGMENT(o);
        return o;
    }

    half4 frag_shadow(v2f_shadow IN) : SV_Target
    {
        half atten = LIGHT_ATTENUATION(IN);
        return half4(_Color.rgb, lerp(_Color.a, 0, atten));
    }

    ENDCG

    SubShader
    {
        Tags { "Queue"="AlphaTest+49" }

        // Depth fill pass
        Pass
        {
            ColorMask 0

            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            struct v2f {
                float4 pos : SV_POSITION;

                float4 someOtherVarying : TEXCOORD0;

                META_DEPTH_VERTEX_OUTPUT(0) // the number should stand for the previous TEXCOORD# + 1

                UNITY_VERTEX_INPUT_INSTANCE_ID
                UNITY_VERTEX_OUTPUT_STEREO // required for stereo
            };

            v2f vert(appdata_full v)
            {
                v2f o;
                UNITY_INITIALIZE_OUTPUT(v2f, o);
                o.pos = UnityObjectToClipPos(v.vertex);;

                // 5. World position is required to calculate the occlusions.
                //    This macro will calculate and set world position value in the output Varyings structure.
                META_DEPTH_INITIALIZE_VERTEX_OUTPUT(o, v.vertex);

                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_TRANSFER_INSTANCE_ID(v, o);

                // 6. Passes stereo information to frag shader
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);

                return o;
            }

            half4 frag(v2f IN) : SV_Target {

               UNITY_SETUP_INSTANCE_ID(IN);

               UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);

               // this is something your shader will return without occlusions
               half4 fragmentShaderResult = _Color;

               // Third field is for environment depth bias. 0.0 means the occlusion will be calculated with depths as they are.
               META_DEPTH_OCCLUDE_OUTPUT_PREMULTIPLY(IN, fragmentShaderResult, 0.0);

               return fragmentShaderResult;
            }

            ENDCG
        }

        // Forward base pass
        Pass
        {
            Tags { "LightMode" = "ForwardBase" }
            Blend SrcAlpha OneMinusSrcAlpha
            CGPROGRAM
            #pragma vertex vert_shadow
            #pragma fragment frag_shadow
            #pragma multi_compile_fwdbase
            // DepthAPI Environment Occlusion
            #pragma multi_compile _ HARD_OCCLUSION SOFT_OCCLUSION
            ENDCG
        }

        // Forward add pass
        Pass
        {
            Tags { "LightMode" = "ForwardAdd" }
            Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha
            CGPROGRAM
            #pragma vertex vert_shadow
            #pragma fragment frag_shadow
            #pragma multi_compile_fwdadd_fullshadows
            // DepthAPI Environment Occlusion
            #pragma multi_compile _ HARD_OCCLUSION SOFT_OCCLUSION
            ENDCG
        }
    }
    FallBack "Mobile/VertexLit"
}

#

vasylbo commented 7 months ago

Hey, @PG13park ! Thanks for trying Depth API. I'll try to help you here, but I'll need more context as I don't have enough details yet. This is what I see so far:

  1. The pass you are adding occlusions to has a comment on top saying it's "Depth fill pass" and "ColorMask 0" so I assume it doesn't render anything.
  2. Also, you didn't add #pragma multi_compile _ HARD_OCCLUSION SOFT_OCCLUSION to that pass, so the macros for aren't getting unwrapped actually.
  3. You have two other passes that do rendering. Judging by the "LightMode" tags in those, to occlude shadows, you'd need to change "ForwardAdd" one.
  4. I see that you've added #pragma multi_compile _ HARD_OCCLUSION SOFT_OCCLUSION there, but it's only declaring what keywords this pass will use to switch between, it doesn't add the implementation.
  5. If I read correctly, "ForwardAdd" seem to use functions from CGINCLUDE section you have on top. It means you just need to add the same steps you did for the first pass but to CGINCLUDE section functions. ie 'v2f_shadow' should get 'META_DEPTH_VERTEX_OUTPUT(2)', 'vert_shadow' should get 'META_DEPTH_INITIALIZE_VERTEX_OUTPUT(o, v.vertex);' and 'frag_shadow' should change to something like:
    half4 frag_shadow(v2f_shadow IN) : SV_Target
    {
        half atten = LIGHT_ATTENUATION(IN);
        half4 fragmentShaderResult = half4(_Color.rgb, lerp(_Color.a, 0, atten));
        META_DEPTH_OCCLUDE_OUTPUT_PREMULTIPLY(IN, fragmentShaderResult, 0.0);
        return fragmentShaderResult;
    }

    Let us know if that helps

PG13park commented 7 months ago

shader

Thanks that makes more sense sorry I am very new to shaders. Here is the original shader I was trying to combine with.

PG13park commented 7 months ago

Thank you guys so much I got it to work!!!! You also helped me understand shaders a lot more.

I am having a problem with the shaders material looking light it z fighting or getting occluded with the ground. (1.) Is there a way I can make a little bit greater threshold on the depth sensor when it occludes things, so the ground doesn't try to occlude my shadows. (2.) Or should I try and make a copy of my global mesh and shrink its scale; by just a slight amount, so its further from the floor and walls and apply the shader material to that? I don't know how accurate scaling down the mesh would be. (3.) Some other solution im not thinking of?

Here is the working shader code if anybody wants it:

Shader "Meta/Depth/BiRP/DepthShadow"
{
    Properties
    {
        _Color ("Shadow Color", Color) = (0, 0, 0, 0.6)
    }

    CGINCLUDE

    #include "UnityCG.cginc"
    #include "AutoLight.cginc"
    #include "Packages/com.meta.xr.depthapi/Runtime/BiRP/EnvironmentOcclusionBiRP.cginc"

    struct v2f_shadow {
        float4 pos : SV_POSITION;
        LIGHTING_COORDS(0, 1)
        META_DEPTH_VERTEX_OUTPUT(2)
        UNITY_VERTEX_INPUT_INSTANCE_ID
        UNITY_VERTEX_OUTPUT_STEREO
    };

    half4 _Color;

    v2f_shadow vert_shadow(appdata_full v)
    {
        v2f_shadow o;
        UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);//maybe move down or add UNITY_SETUP_INSTANCE_ID(v); if it doesnt work.
        o.pos = UnityObjectToClipPos(v.vertex);
        META_DEPTH_INITIALIZE_VERTEX_OUTPUT(o, v.vertex);
        TRANSFER_VERTEX_TO_FRAGMENT(o);
        return o;
    }

    half4 frag_shadow(v2f_shadow IN) : SV_Target
    {
        UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);

        half atten = LIGHT_ATTENUATION(IN);
        half4 fragmentShaderResult = half4(_Color.rgb, lerp(_Color.a, 0, atten));
        META_DEPTH_OCCLUDE_OUTPUT_PREMULTIPLY(IN, fragmentShaderResult, 0.0);
        return fragmentShaderResult;
    }

    ENDCG

    SubShader
    {
        Tags { "Queue"="AlphaTest+49" }

        // Depth fill pass
        Pass
        {
            ColorMask 0

            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            struct v2f {
                float4 pos : SV_POSITION;
            };

            v2f vert(appdata_full v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos (v.vertex);
                return o;
            }

            half4 frag(v2f IN) : SV_Target
            {
                return (half4)0;
            }

            ENDCG
        }

        // Forward base pass
        Pass
        {
            Tags { "LightMode" = "ForwardBase" }
            Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha
            CGPROGRAM
            #pragma vertex vert_shadow
            #pragma fragment frag_shadow
            #pragma multi_compile_fwdbase
            #pragma multi_compile _ HARD_OCCLUSION SOFT_OCCLUSION
            ENDCG
        }

        // Forward add pass
        Pass
        {
            Tags { "LightMode" = "ForwardAdd" }
            Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha
            CGPROGRAM
            #pragma vertex vert_shadow
            #pragma fragment frag_shadow
            #pragma multi_compile_fwdadd_fullshadows
            #pragma multi_compile _ HARD_OCCLUSION SOFT_OCCLUSION
            ENDCG
        }
    }
    FallBack "Mobile/VertexLit"
}
vasylbo commented 7 months ago

Great, nice to hear!

1) We have a scene in samples that showcases how to mitigate the z-fighting issue. It's called SceneAPIPlacement. What happens there is the you replace the 0.0 in META_DEPTH_OCCLUDE_OUTPUT_PREMULTIPLY call with an Environment Depth Bias value of choice. You can start with 0.06 and tweak to your liking.

2) If Z-fighting happens with the geometry and not the Environment depth, then you can use Unity's built-in depth bias functionality. It's called Offset (https://docs.unity3d.com/Manual/SL-Offset.html).

3) The two above should cover most of use cases.

PG13park commented 7 months ago

Ok I thought I read about some value to change. Thank you guys so much.

PG13park commented 6 months ago

Hey I was just trying to add a point light in my scene instead of a directional light, and since the occluded shadows shader is a lit shader the material catches all the light and I do not want that. If I make the above shader unlit, would the shadows also dissapear? What im wondering is how can I make the shader above only show shadows, but not recive light.

TudorJude commented 6 months ago

Check out MRUK's Passthrough relighting feature.

PG13park commented 6 months ago

I just checked it out and it still doesn't solve my problem. All I need is to make it so the shader a few comments up only recives shadows, without lighting the whole mesh. Its ok if the shadows have lighting applied, but nothing else should get lighting.

TudorJude commented 1 month ago

Hello,

Sorry for the late reply. Did you manage to overcome the issue?

PG13park commented 1 month ago

No, It works great with a directional light, so I have just been using that, but I would love to use point-lights instead, but as said earlier they light the whole mesh instead of just casting shadows.