Shader "Custom/DepthNormalShader" {
    Properties{
        _DepthMin("Depth Min", Range(0, 10)) = 0
        _DepthMax("Depth Max", Range(0, 30)) = 10
    }

        // SubShader block contains the actual shader code
        SubShader{
        // Tags determine rendering order and other options
        Tags { "Queue" = "Transparent" "RenderType" = "Transparent" }

        // Pass block contains a single rendering pass
        Pass {
            // Start of a Cg/HLSL block
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            // Declare the data structure for input to the vertex shader
            struct appdata {
                float4 vertex : POSITION;  // The vertex position
                float2 uv : TEXCOORD0;     // The first texture coordinate
            };

            // Declare the data structure for output from the vertex shader and input to the fragment shader
            struct v2f {
                float2 uv : TEXCOORD0;         // The passed through texture coordinate
                float4 vertex : SV_POSITION;   // The computed vertex position
            };

            // Vertex shader function
            v2f vert(appdata v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);   // Transform vertex from object space to clip space
                o.uv = v.uv;                                 // Pass through the texture coordinate
                return o;
            }

            // Declare some variables that will be used in the fragment shader
            sampler2D _CameraDepthNormalsTexture;   // Sampler for the camera's depth normals texture
            float4x4 _viewToWorld;                  // Matrix to convert from view space to world space
            float _DepthMin;                        // Minimum depth
            float _DepthMax;                        // Maximum depth

            // Function to remap a value from one range to another
            float Remap(float value, float fromMin, float fromMax, float toMin, float toMax) {
                return (value - fromMin) / (fromMax - fromMin) * (toMax - toMin) + toMin;
            }

            // Fragment shader function
            fixed4 frag(v2f i) : SV_Target{
                // Sample the camera's depth normals texture at the current texture coordinate
                // This texture contains both depth and normal information packed into a single value
                float4 depthNormal = tex2D(_CameraDepthNormalsTexture, i.uv);

                // Declare some variables to hold the decoded normal and depth
                // We need to unpack these values from the depthNormal to use them separately
                float3 normal;
                float depth;

                // Decode the depth and normal from the sampled depthNormal value
                // Unity provides a DecodeDepthNormal function to perform this operation
                DecodeDepthNormal(depthNormal, depth, normal);

                // Convert the normal from view space to world space
                // This allows us to work with normals that are independent of the camera's orientation
                normal = mul((float3x3)_viewToWorld, normal);

                // The depth value is currently in non-linear depth space, so we convert it to linear depth space
                // Linear depth space makes it easier to work with depth values and map them to a specific range
                depth = Linear01Depth(depth);

                // Remap the depth value from the range 0 to 1 to the range _DepthMin to _DepthMax
                // This customizes the depth range to provide better control over the final appearance
                depth = Remap(depth, 0, 1, _DepthMin, _DepthMax);

                // Clamps the depth value to the range 0 to 1.
                // This ensures that the depth value will be in a valid range for display and further calculations
                depth = clamp(depth, 0, 1);

                // The normal value is currently in the range -1 to 1, so we convert it to the range 0 to 1
                float3 normalColor = normal * 0.5 + 0.5;

                // Combine the depth and normalColor values
                float3 combinedColor = depth * normalColor;

                // Return a color with the combinedColor for RGB and full opacity for alpha
                return fixed4(combinedColor, 1);
            }

            ENDCG
        }
    }
}
