﻿// NOTE: Based on URP Lighting.hlsl which replaced some half3 with floats to avoid lighting artifacts on mobile

Shader "Lux URP/Water"
{
    Properties
    {
        [HeaderHelpLuxURP_URL(pwa0yoxc3z5m)]

        [Header(Surface Options)]
        [Space(8)]
        [Enum(Off,0,On,1)]_ZWrite       ("ZWrite", Float) = 1.0
        [Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("ZTest", Float) = 4 // "LessEqual"
        // [Enum(UnityEngine.Rendering.CullMode)] _Culling ("Culling", Float) = 0
        [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend("Dest BlendMode", Float) = 0

        [ToggleOff(_RECEIVE_SHADOWS_OFF)]
        _ReceiveShadows                 ("Receive Shadows", Float) = 1.0
        [Toggle(ORTHO_SUPPORT)]
        _OrthoSpport                    ("Enable Orthographic Support", Float) = 0

        [Header(Surface Inputs)]
        [Space(8)]
        _BumpMap                        ("Water Normal Map", 2D) = "bump" {}
        _BumpScale                      ("Normal Scale", Float) = 1.0
        [LuxURPVectorTwoDrawer]
        _Speed                          ("Speed (UV)", Vector) = (0.1, 0, 0, 0)
        [LuxURPVectorFourDrawer] 
        _SecondaryTilingSpeedRefractBump("Secondary Bump", Vector) = (2, 2.3, 0.1, 1)
        [LuxURPHelpDrawer] _Help       ("Tiling (X) Speed (Y) Refraction (Z) Bump Scale (W)", Float) = 1
        [Space(5)]
        _Smoothness                     ("Smoothness", Range(0.0, 1.0)) = 0.5
        _SpecColor                      ("Specular", Color) = (0.2, 0.2, 0.2)
        [Space(5)]
        _EdgeBlend                      ("Edge Blending", Range(0.1, 10.0)) = 2.0 

        [Space(5)]
        [Toggle(_REFRACTION)]
        _EnableRefraction               ("Enable Refraction", Float) = 1
        _Refraction                     ("     Refraction", Range(0, 1)) = .25
        
        _ReflectionBumpScale            ("Reflection Bump Scale", Range(0.1, 1.0)) = 0.3

        [Header(Underwater Fog)]
        [Space(8)]
        _Color                          ("Fog Color", Color) = (.2,.8,.9,1)
        _Density                        ("Density", Float) = 1.0

        [Header(Foam)]
        [Space(8)]
        [Toggle(_FOAM)] _Foam           ("Enable Foam", Float) = 1.0
        [NoScaleOffset] _FoamMap        ("Foam Albedo (RGB) Mask (A)", 2D) = "bump" {}
        _FoamTiling                     ("Foam Tiling", Float) = 2
        [LuxURPVectorTwoDrawer]
        _FoamSpeed                      ("Foam Speed (UV)", Vector) = (0.1, 0, 0, 0)
        _FoamScale                      ("Foam Scale", Float) = 4
        _FoamSoftIntersectionFactor     ("Foam Edge Blending", Range(0.1, 3.0)) = 0.5
        _FoamSlopStrength               ("Foam Slope Strength", Range(0.0, 1.0)) = 0.85
        _FoamSmoothness                 ("Foam Smoothness", Range(0.0, 1.0)) = 0.3

        [Header(Advanced)]
        [Space(8)]
        [ToggleOff] _SpecularHighlights ("Enable Specular Highlights", Float) = 1.0
        [ToggleOff]
        _EnvironmentReflections         ("Environment Reflections", Float) = 1.0

    //  As URP 10.1 complains about it?!: 
        [HideInInspector] _Alpha ("Dummy", Float) = 1
        [HideInInspector] _FresnelPower ("Dummy", Float) = 1
        

    }
    SubShader
    {
        Tags
        {
            "RenderPipeline" = "UniversalPipeline"
            "RenderType"="Transparent"
            "Queue"="Transparent"
        }
        LOD 300

        Pass
        {
            Tags {"LightMode" = "UniversalForward"}
//          Blend SrcAlpha OneMinusSrcAlpha
            Blend One [_DstBlend]
            Cull Back
            ZTest [_ZTest]
            ZWrite [_ZWrite]

            HLSLPROGRAM
            // Required to compile gles 2.0 with standard srp library
            #pragma prefer_hlslcc gles
            #pragma exclude_renderers d3d11_9x
            #pragma target 2.0

            // -------------------------------------
            // Universal Pipeline keywords
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
            #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
            #pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
            #pragma multi_compile_fragment _ _SHADOWS_SOFT
            #pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
            #pragma multi_compile _ SHADOWS_SHADOWMASK

            #pragma shader_feature_local_fragment _SPECULARHIGHLIGHTS_OFF
            #pragma shader_feature_local_fragment _ENVIRONMENTREFLECTIONS_OFF
            #pragma shader_feature_local _RECEIVE_SHADOWS_OFF

            #pragma shader_feature_local_fragment _FOAM
            #pragma shader_feature_local_fragment ORTHO_SUPPORT
            #pragma shader_feature_local_fragment _REFRACTION

// #define _ADDITIONAL_LIGHTS_VERTEX
            
            // -------------------------------------
            // Unity defined keywords
            #pragma multi_compile _ DIRLIGHTMAP_COMBINED
            #pragma multi_compile _ LIGHTMAP_ON
            #pragma multi_compile_fog

            //--------------------------------------
            // GPU Instancing
            #pragma multi_compile_instancing
            // #pragma multi_compile _ DOTS_INSTANCING_ON // needs shader target 4.5

            #define _SPECULAR_SETUP 1
            #define _NORMALMAP 1

            #pragma vertex vert
            #pragma fragment frag

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        //  defines a bunch of helper functions (like lerpwhiteto)
            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl"
        //  defines SurfaceData, textures and the functions Alpha, SampleAlbedoAlpha, SampleNormal, SampleEmission
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl"

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"

            struct VertexInput
            {
                float4 positionOS   : POSITION;
                float3 normalOS     : NORMAL;
                float4 tangentOS    : TANGENT;
                float2 texcoord     : TEXCOORD0;
                float2 lightmapUV   : TEXCOORD1;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct VertexOutput
            {
                float4 positionCS : SV_POSITION;
                float4 uv : TEXCOORD0;                          // xy textccord, zw water

                DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, 1);

                float3 positionWS               : TEXCOORD2;
                
                #ifdef _NORMALMAP
                    half4 normalWS              : TEXCOORD3;    // xyz: normal, w: viewDir.x
                    half4 tangentWS             : TEXCOORD4;    // xyz: tangent, w: viewDir.y
                    half4 bitangentWS           : TEXCOORD5;    // xyz: bitangent, w: viewDir.z
                #else
                    half3 normalWS              : TEXCOORD3;
                    half3 viewDirWS             : TEXCOORD4;
                #endif

                half4 fogFactorAndVertexLight   : TEXCOORD6; // x: fogFactor, yzw: vertex light
                #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
                    float4 shadowCoord          : TEXCOORD7;
                #endif
                UNITY_VERTEX_INPUT_INSTANCE_ID
                UNITY_VERTEX_OUTPUT_STEREO
            };

            CBUFFER_START(UnityPerMaterial)
                float _Alpha;
                half4 _SpecColor;
                half _Smoothness;
                half _EdgeBlend;
                float2 _Speed;
                half _BumpScale;
                float4 _SecondaryTilingSpeedRefractBump;
                half4 _Color;
                half _Density;
                half _FresnelPower;
                half _Refraction;
                half _ReflectionBumpScale;
                half _FoamScale;
                half _FoamTiling;
                half2 _FoamSpeed;
                half _FoamSoftIntersectionFactor;
                half _FoamSlopStrength;
                half _FoamSmoothness;
                float4 _BumpMap_ST;
            CBUFFER_END

        //  Defined in SurfaceInput.hlsl
        //  TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap);
            
            #if defined(SHADER_API_GLES)
                TEXTURE2D(_CameraDepthTexture); SAMPLER(sampler_CameraDepthTexture);
                //TEXTURE2D(_CameraOpaqueTexture); SAMPLER(sampler_CameraOpaqueTexture);
            #else
                // URP 7.1.5.
                TEXTURE2D_X_FLOAT(_CameraDepthTexture);
                //SAMPLER(sampler_PointClamp); // Using Load means no sampling or filtering anyway
            #endif
            TEXTURE2D_X(_CameraOpaqueTexture);
            SAMPLER(sampler_LinearClamp);
            SAMPLER(sampler_PointClamp);
            float4 _CameraDepthTexture_TexelSize;
            float4 _CameraOpaqueTexture_TexelSize;
            float4 _CameraOpaqueTexture_ST;

            TEXTURE2D(_FoamMap); SAMPLER(sampler_FoamMap); float4 _FoamMap_TexelSize;
   
            VertexOutput vert (VertexInput input)
            {
                VertexOutput output = (VertexOutput)0;
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_TRANSFER_INSTANCE_ID(input, output);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

                //o.positionWS = TransformObjectToWorld(input.positionOS.xyz); //  mul(UNITY_MATRIX_M, input.vertex).xyz;
                //o.positionCS = TransformWorldToHClip(o.positionWS.xyz); // TransformObjectToHClip(input.positionOS.xyz);
                
                VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
                output.positionWS = vertexInput.positionWS;
                output.positionCS = vertexInput.positionCS;
                VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);

                #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
                    output.shadowCoord = GetShadowCoord(vertexInput);
                #endif
                
                #ifdef _NORMALMAP
                    float3 viewDirWS = GetCameraPositionWS() - output.positionWS;
                    output.normalWS = half4(normalInput.normalWS, viewDirWS.x);
                    output.tangentWS = half4(normalInput.tangentWS, viewDirWS.y);
                    output.bitangentWS = half4(normalInput.bitangentWS, viewDirWS.z);
                #else
                    output.normalWS.xyz = NormalizeNormalPerVertex(normalInput.normalWS);
                    output.viewDirWS = GetCameraPositionWS() - o.positionWS;
                #endif

                half fogFactor = ComputeFogFactor(output.positionCS.z);
                half3 vertexLight = VertexLighting(output.positionWS, output.normalWS.xyz);

                OUTPUT_LIGHTMAP_UV(input.lightmapUV, unity_LightmapST, output.lightmapUV);
                OUTPUT_SH(output.normalWS.xyz, output.vertexSH);
                output.fogFactorAndVertexLight = half4(fogFactor, vertexLight);

                output.uv.xy = TRANSFORM_TEX(input.texcoord, _BumpMap) + _Time.xx * _Speed;

            //  Water
            //  see: ComputeGrabScreenPos
                float4 screenUV = ComputeScreenPos(output.positionCS);
                output.uv.zw = screenUV.xy; //waterDepth.xx;

                return output;
            }


        //  ------------------------------------------------------------------
        //  Helper functions to handle orthographic / perspective projection  

            inline float GetOrthoDepthFromZBuffer (float rawDepth) {
                #if defined(UNITY_REVERSED_Z)
                //  Needed to handle openGL
                    #if UNITY_REVERSED_Z == 1
                        rawDepth = 1.0f - rawDepth;
                    #endif
                #endif
                return lerp(_ProjectionParams.y, _ProjectionParams.z, rawDepth);
            }

            inline float GetProperEyeDepth (float rawDepth) {
                #if defined(ORTHO_SUPPORT)
                    float perspectiveSceneDepth = LinearEyeDepth(rawDepth, _ZBufferParams);
                    float orthoSceneDepth = GetOrthoDepthFromZBuffer(rawDepth);
                    return lerp(perspectiveSceneDepth, orthoSceneDepth, unity_OrthoParams.w);
                #else
                    return LinearEyeDepth(rawDepth, _ZBufferParams);
                #endif
            }


            half4 frag (VertexOutput input) : SV_Target
            {
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

                //half3 albedo = 0;
                //half metallic = 0;
                half3 specular = _SpecColor.rgb;
                half smoothness = _Smoothness;
                half occlusion = 1;
                half emission = 0;
                half alpha = 1;
                half3 normalTS = half3(0,0,1);
                half3 refraction = 0;

                #if defined(ORTHO_SUPPORT)
                    float surfaceEyeDepth = GetProperEyeDepth(input.positionCS.z); // LinearEyeDepth(input.positionCS.z, _ZBufferParams);
                #else
                    float surfaceEyeDepth = input.positionCS.w;
                #endif


            //  We have to reset i.grabUV.w as otherwise texture projection does not work
                #if defined(ORTHO_SUPPORT)
                    input.positionCS.w = lerp(input.positionCS.w, 1.0f, unity_OrthoParams.w);
                #endif

                float2 screenUV = input.uv.zw / input.positionCS.w;

            //  Fix screenUV for Single Pass Stereo Rendering
                #if defined(UNITY_SINGLE_PASS_STEREO)
                    screenUV.xy = UnityStereoTransformScreenSpaceTex(screenUV.xy);
                #endif

                half4 normalSample = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, input.uv.xy);

            //  ////////////
            //  Get the normals
                #if BUMP_SCALE_NOT_SUPPORTED
                    normalTS =  UnpackNormal(normalSample);
                    normalSample = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, input.uv.xy * _SecondaryTilingSpeedRefractBump.x + _Time.xx * _Speed * _SecondaryTilingSpeedRefractBump.y + normalTS.xz * _SecondaryTilingSpeedRefractBump.z );
                    half3 detailNormal = UnpackNormal(normalSample);
                    normalTS = normalize(half3(normalTS.xy + detailNormal.xy, normalTS.z * detailNormal.z)); 
                #else
                    normalTS = UnpackNormalScale(normalSample, _BumpScale);
                    normalSample = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, input.uv.xy * _SecondaryTilingSpeedRefractBump.x + _Time.xx * _Speed * _SecondaryTilingSpeedRefractBump.y + normalTS.xz * _SecondaryTilingSpeedRefractBump.z );
                    half3 detailNormal = UnpackNormalScale(normalSample, _SecondaryTilingSpeedRefractBump.w);
                    normalTS = normalize(half3(normalTS.xy + detailNormal.xy, normalTS.z * detailNormal.z)); 
                #endif
            
            //  World space normal - as we need it for view space normal (skipped)
                half3 normalWS = TransformTangentToWorld(normalTS, half3x3(input.tangentWS.xyz, input.bitangentWS.xyz, input.normalWS.xyz));
                normalWS = NormalizeNormalPerPixel(normalWS);

            //  ////////////
            //  Refraction
            //  Skipped view space normal and went with tangent space instead
                //half3 viewNormal = mul((float3x3)GetWorldToHClipMatrix(), -normalWS).xyz;
                //float2 offset = viewNormal.xz * _Refraction;

                float distanceFadeFactor = input.positionCS.z * _ZBufferParams.z;

            //  OpenGL Core
                #if UNITY_REVERSED_Z != 1
                    distanceFadeFactor = input.positionCS.z / input.positionCS.w;
                #endif

            //  Somehow handle orthographic projection
                #if defined(ORTHO_SUPPORT)
                    distanceFadeFactor = (unity_OrthoParams.w) ? 1.0f / unity_OrthoParams.x : distanceFadeFactor;
                #endif

                #if defined(_REFRACTION)
                    float2 offset = normalTS.xy * _Refraction * distanceFadeFactor;
                #else
                    float2 offset = 0;
                #endif 

// URP 7.1.5.: We have to use saturate(screenUV + offset) and saturate(offset)
// GLES 2.0 does not support LOAD_TEXTURE2D_X. LOAD_TEXTURE2D_X does not clamp even if we use saturate? * 0.9999f solves this.

                #if defined(SHADER_API_GLES)
                    float refractedSceneDepth = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, sampler_CameraDepthTexture, screenUV + offset, 0);
                #else
                    float refractedSceneDepth = LOAD_TEXTURE2D_X(_CameraDepthTexture, _CameraDepthTexture_TexelSize.zw * saturate(screenUV + offset) * 0.9999f ).x;
                    //float refractedSceneDepth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, saturate(screenUV + offset)).x;
                #endif
                refractedSceneDepth = GetProperEyeDepth(refractedSceneDepth);
                float viewDepth = refractedSceneDepth - surfaceEyeDepth;
            
            //  Do not refract pixel of the foreground
                #if defined(_REFRACTION)
                    offset = screenUV + offset * saturate(viewDepth);
                    
                    #if defined(SHADER_API_GLES)
                        refractedSceneDepth = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, sampler_CameraDepthTexture, offset, 0);   
                    #else
                        refractedSceneDepth = LOAD_TEXTURE2D_X(_CameraDepthTexture, (_CameraDepthTexture_TexelSize.zw * saturate(offset) * 0.9999f  )).x;
                        //refractedSceneDepth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, saturate(offset)).x;
                    #endif
                    refractedSceneDepth = GetProperEyeDepth(refractedSceneDepth);
                    refraction = SAMPLE_TEXTURE2D_X(_CameraOpaqueTexture, sampler_LinearClamp, saturate(offset)).rgb;
                    viewDepth = refractedSceneDepth - surfaceEyeDepth;

                //  In case we use HDR refraction may get way too bright.
                    refraction = saturate(refraction);
                #endif

            //  Final blend value
                alpha = saturate ( _EdgeBlend * viewDepth );

            //  ////////////
            //  Underwater fog
            //  Calculate Attenuation along viewDirection
                float viewAtten = saturate( 1.0 - exp( -viewDepth * _Density) );
                float underwaterFogDensity = viewAtten;

            //  ////////////
            //  Foam
                #if defined(_FOAM)

                /*
                //  We might do a 3rd unrefracted sample here - but it indroduces some kind of ghosting.
                    #if defined(SHADER_API_GLES)
                        refractedSceneDepth = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, sampler_CameraDepthTexture, screenUV, 0);
                    #else
                        refractedSceneDepth = LOAD_TEXTURE2D_X(_CameraDepthTexture, _CameraDepthTexture_TexelSize.zw * screenUV).x;
                    #endif
                    refractedSceneDepth = GetProperEyeDepth(refractedSceneDepth);
                    viewDepth = refractedSceneDepth - surfaceEyeDepth;
                */

                    half FoamSoftIntersection = saturate( _FoamSoftIntersectionFactor * (viewDepth ));
                    half FoamThreshold = normalTS.z * 2 - 1;
                //  Get shoreline foam mask
                    float shorelineFoam = saturate(-FoamSoftIntersection * (1 + FoamThreshold) + 1 );
                    shorelineFoam = shorelineFoam * saturate(1 * FoamSoftIntersection - FoamSoftIntersection * FoamSoftIntersection );
                    half4 rawFoamSample = SAMPLE_TEXTURE2D(_FoamMap, sampler_FoamMap, input.uv.xy * _FoamTiling + normalTS.xy * 0.02 + _Time.xx * _FoamSpeed);
                //  Add foam on slopes
                    shorelineFoam += saturate(1 - input.normalWS.y) * _FoamSlopStrength;
                //  Combine sample and distribution(shorelineFoam)
                    rawFoamSample.a = saturate(rawFoamSample.a * shorelineFoam * _FoamScale  * ( 1 - (normalTS.x + normalTS.y) * 4) );
                //  Errode foam
                    rawFoamSample.a = rawFoamSample.a * smoothstep( 0.8 - rawFoamSample.a, 1.6 - rawFoamSample.a, rawFoamSample.a );
                //  Adjust smoothess to foam
                    smoothness = lerp(smoothness, _FoamSmoothness, rawFoamSample.a);
                #endif


            //  ////////////    
            //  Transfer all to world space and prepare inputData (for convenience)
                InputData inputData = (InputData)0;
                inputData.positionWS = input.positionWS;

                #ifdef _NORMALMAP
                    inputData.normalWS = normalWS;
                    inputData.viewDirectionWS = SafeNormalize( float3(input.normalWS.w, input.tangentWS.w, input.bitangentWS.w) );
                #else
                    inputData.normalWS = input.normalWS.xyz; // no normal map
                    inputData.viewDirectionWS = SafeNormalize(input.viewDirWS);
                #endif

//  Refract shadows / * input.positionCS.w because unity will divide                
/*
#if defined(_MAIN_LIGHT_SHADOWS)
    #if SHADOWS_SCREEN
    
        #if defined(_REFRACTION)
            inputData.shadowCoord = float4(offset * input.positionCS.w, input.shadowCoord.zw);
        #else
            inputData.shadowCoord = float4(screenUV * input.positionCS.w, input.shadowCoord.zw);
        #endif
    #else
        inputData.shadowCoord = input.shadowCoord;
    #endif
#else
    inputData.shadowCoord = float4(0, 0, 0, 0);
#endif
*/
  
            //  No refracted shadows any more...
                #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
                    inputData.shadowCoord = input.shadowCoord;
                #elif defined(MAIN_LIGHT_CALCULATE_SHADOWS)
                    inputData.shadowCoord = TransformWorldToShadowCoord(inputData.positionWS);
                #else
                    inputData.shadowCoord = float4(0, 0, 0, 0);
                #endif


            //  Fix shadowCoord for Single Pass Stereo Rendering
                #if defined(UNITY_SINGLE_PASS_STEREO)
                    #if SHADOWS_SCREEN
                    //  Shadows perform : UnityStereoTransformScreenSpaceTex(shadowCoord.xy) after perspective division;
                    //  We do it manually:        
                        inputData.shadowCoord.xy =  inputData.shadowCoord.xy / inputData.shadowCoord.w;
                        inputData.shadowCoord.w = 1.0f;
                    //  inputData.shadowCoord.x = screenUV.x;
                    //  Then we reset shadowCoord.w and unity_StereoScaleOffset so it does not get applied twice
                        unity_StereoScaleOffset[0] = float4(1,1,0,0);
                        unity_StereoScaleOffset[1] = float4(1,1,0,0);
                    #endif
                #endif


                inputData.fogCoord = input.fogFactorAndVertexLight.x;
                inputData.vertexLighting = input.fogFactorAndVertexLight.yzw;
                inputData.bakedGI = SAMPLE_GI(input.lightmapUV, input.vertexSH, inputData.normalWS);

                inputData.shadowMask = SAMPLE_SHADOWMASK(input.lightmapUV);

            //  /////////
            //  Apply lighting
                half4 color = 1;
                half3 origRefraction = refraction;

            //  Get fog
                real fogFactor = input.fogFactorAndVertexLight.x;
                #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
                    #if defined(FOG_EXP)
                        fogFactor = saturate(exp2(-fogFactor));
                    #elif defined(FOG_EXP2)
                        fogFactor = saturate(exp2(-fogFactor*fogFactor));
                    #endif
                #endif

            //  Prepare missing Inputs
                half reflectivity = ReflectivitySpecular(specular);
                half oneMinusReflectivity = 1.0 - reflectivity;
                half perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness);
                half roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
                half roughness2 = roughness * roughness;
                half normalizationTerm = roughness * 4.0h + 2.0h;

            //  ShadowMask: To ensure backward compatibility we have to avoid using shadowMask input, as it is not present in older shaders
                #if defined(SHADOWS_SHADOWMASK) && defined(LIGHTMAP_ON)
                    half4 shadowMask = inputData.shadowMask;
                #elif !defined (LIGHTMAP_ON)
                    half4 shadowMask = unity_ProbesOcclusion;
                #else
                    half4 shadowMask = half4(1, 1, 1, 1);
                #endif

            //  Get light
                //Light mainLight = GetMainLight(inputData.shadowCoord);
                Light mainLight = GetMainLight(inputData.shadowCoord, inputData.positionWS, shadowMask);


                half3 lightColorAndAttenuation = mainLight.color * (mainLight.distanceAttenuation * mainLight.shadowAttenuation);

half3 shad =  lightColorAndAttenuation;               

                MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, half4(0, 0, 0, 0));

                #ifdef _ADDITIONAL_LIGHTS
                    int pixelLightCount = GetAdditionalLightsCount();
                #endif

                half NdotL = saturate(dot( inputData.normalWS, mainLight.direction));
                half3 VertexAndGILighting = input.fogFactorAndVertexLight.yzw + inputData.bakedGI;

            //  Diffuse underwater lighting
                half diffuse_nl = saturate(dot(half3(0,1,0), mainLight.direction));
                //half3 diffuseUnderwaterLighting = _Color * (lightColorAndAttenuation * diffuse_nl + VertexAndGILighting);
            //  Shadows are sampled at the bottom surface. So we attenuate them by underwaterFogDensity. Just a hack but it looks better than not doing anything here.
                half3 diffuseUnderwaterLighting = _Color.rgb * (VertexAndGILighting + (diffuse_nl * 
                    mainLight.color * mainLight.distanceAttenuation * 
                    lerp( mainLight.shadowAttenuation, 1 , underwaterFogDensity )
                    )
                );

            //  Add foam
                #if defined(_FOAM)
                    half3 foamLighting = rawFoamSample.rgb * (lightColorAndAttenuation * NdotL + VertexAndGILighting);
                #endif
            //  Specular Lighting
                half3 specularLighting = 0;
                #if !defined(_SPECULARHIGHLIGHTS_OFF)
                    float3 halfDir = SafeNormalize(float3(mainLight.direction) + float3(inputData.viewDirectionWS));
                    float NoH = saturate(dot(inputData.normalWS, halfDir));
                    half LoH = saturate(dot(mainLight.direction, halfDir));
                    float d = NoH * NoH * (roughness2 - 1.h) + 1.0001f;
                    half LoH2 = LoH * LoH;
                    half specularTerm = roughness2 / ((d * d) * max(0.1h, LoH2) * normalizationTerm );
                    #if defined (SHADER_API_MOBILE)
                        specularTerm = specularTerm - HALF_MIN;
                        specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles
                    #endif
                    specularLighting = specularTerm * specular * lightColorAndAttenuation;
                    specularLighting *= NdotL;
                #endif
                
                #ifdef _ADDITIONAL_LIGHTS
                    for (int i = 0; i < pixelLightCount; ++i) {
                        Light light = GetAdditionalLight(i, inputData.positionWS);
                        NdotL = saturate(dot(inputData.normalWS, light.direction));
                        diffuse_nl = saturate(dot(half3(0,1,0), light.direction));
                        
                        half3 addLightColorAndAttenuation = light.color * light.distanceAttenuation * light.shadowAttenuation;
                        
                        diffuseUnderwaterLighting += _Color.rgb * addLightColorAndAttenuation * diffuse_nl;
                        #if defined(_FOAM)
                            foamLighting += rawFoamSample.rgb * addLightColorAndAttenuation * NdotL;
                        #endif

                        #if !defined(_SPECULARHIGHLIGHTS_OFF)
                            halfDir = SafeNormalize(float3(light.direction) + float3(inputData.viewDirectionWS));
                            NoH = saturate(dot(inputData.normalWS, halfDir));
                            LoH = saturate(dot(light.direction, halfDir));
                            d = NoH * NoH * (roughness2 - 1.h) + 1.0001f;
                            LoH2 = LoH * LoH;
                            specularTerm = roughness2 / ((d * d) * max(0.1h, LoH2) * normalizationTerm );
                            #if defined (SHADER_API_MOBILE)
                                specularTerm = specularTerm - HALF_MIN;
                                specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles
                            #endif
                            specularLighting += specularTerm * specular * addLightColorAndAttenuation;
                        #endif
                    }
                #endif

            //  Fog - diffuseUnderwaterLighting
                #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
                    #if defined(_REFRACTION)
                        diffuseUnderwaterLighting = lerp(unity_FogColor.rgb, diffuseUnderwaterLighting, fogFactor);
                    #endif
                #endif
            
            //  Add underwater fog
                #if defined(_REFRACTION)
                    refraction.rgb = lerp(refraction.rgb, diffuseUnderwaterLighting, underwaterFogDensity);
                #else
            //  Handle transparent mode
                    refraction.rgb = diffuseUnderwaterLighting * underwaterFogDensity; // premul
                #endif
                
            //  Fog – foam
                #if defined(_FOAM) && defined(_REFRACTION)
                    #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
                        foamLighting = lerp(unity_FogColor.rgb, foamLighting, fogFactor);
                    #endif
                #endif

            //  Reflections
                #if !defined(_ENVIRONMENTREFLECTIONS_OFF)
                //  Calculate smoothedReflectionNormal
                    half3 reflectionNormal = lerp( input.normalWS.xyz, inputData.normalWS, _ReflectionBumpScale);
                    half3 reflectionVector = reflect(-inputData.viewDirectionWS, reflectionNormal);
                    half fresnelTerm = Pow4(1.0 - saturate(dot(inputData.normalWS, inputData.viewDirectionWS)));
                    half3 reflections = GlossyEnvironmentReflection(reflectionVector, perceptualRoughness, occlusion);
                    float surfaceReduction = 1.0 / (roughness2 + 1.0);
                    half grazingTerm = saturate(smoothness + reflectivity);
                    reflections = reflections * surfaceReduction * lerp(specular, grazingTerm, fresnelTerm);
                //  Combine specular lighting and reflections 
                    specularLighting += reflections;
                #endif

                #if !defined(_SPECULARHIGHLIGHTS_OFF) || !defined(_ENVIRONMENTREFLECTIONS_OFF)
                    #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
                    //  "Apply" fog
                        #if defined(_REFRACTION)
                            specularLighting *= fogFactor;
                        #endif
                    #endif
                #endif

            //  Combine all
                color.rgb = refraction.rgb;
                #if defined(_FOAM)            
                    color.rgb = lerp(color.rgb, foamLighting, rawFoamSample.a );
                #endif
                #if !defined(_SPECULARHIGHLIGHTS_OFF) || !defined(_ENVIRONMENTREFLECTIONS_OFF)
                    color.rgb += specularLighting;
                #endif

            //  Soft edge blending
                #if defined(_REFRACTION)
                    color.rgb = lerp(origRefraction, color.rgb, alpha.xxx );
                #else
            //  Transparent mode
                    #if defined(_FOAM)
                        float visibility = saturate(underwaterFogDensity + rawFoamSample.a) * oneMinusReflectivity + reflectivity;
                    #else
                        float visibility = underwaterFogDensity * oneMinusReflectivity + reflectivity;
                    #endif
                    #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
                        color.rgb = lerp(unity_FogColor.rgb * visibility, color.rgb, fogFactor );
                    #endif
                    color.rgb *= alpha;
                    color.a = alpha * visibility;
                #endif


//color.rgb = shad;
//color.rgb = refractedSceneDepth;
//color.rgb = surfaceEyeDepth;
//color.rgb = viewDepth;

                return color;
            }
            ENDHLSL
        }
    }
}