// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)

    #ifndef UNITY_CG_INCLUDED
    #define UNITY_CG_INCLUDED
    
    #define UNITY_PI            3.14159265359f
    #define UNITY_TWO_PI        6.28318530718f
    #define UNITY_FOUR_PI       12.56637061436f
    #define UNITY_INV_PI        0.31830988618f
    #define UNITY_INV_TWO_PI    0.15915494309f
    #define UNITY_INV_FOUR_PI   0.07957747155f
    #define UNITY_HALF_PI       1.57079632679f
    #define UNITY_INV_HALF_PI   0.636619772367f
    
    // Should SH (light probe / ambient) calculations be performed?
    // - When both static and dynamic lightmaps are available, no SH evaluation is performed
    // - When static and dynamic lightmaps are not available, SH evaluation is always performed
    // - For low level LODs, static lightmap and real-time GI from light probes can be combined together
    // - Passes that don't do ambient (additive, shadowcaster etc.) should not do SH either.
    #define UNITY_SHOULD_SAMPLE_SH (defined(LIGHTPROBE_SH) && !defined(UNITY_PASS_FORWARDADD) && !defined(UNITY_PASS_PREPASSBASE) && !defined(UNITY_PASS_SHADOWCASTER) && !defined(UNITY_PASS_META))
    
    #include "UnityShaderVariables.cginc"
    #include "UnityShaderUtilities.cginc"
    #include "UnityInstancing.cginc"
    
    #ifdef UNITY_COLORSPACE_GAMMA
    #define unity_ColorSpaceGrey fixed4(0.5, 0.5, 0.5, 0.5)
    #define unity_ColorSpaceDouble fixed4(2.0, 2.0, 2.0, 2.0)
    #define unity_ColorSpaceDielectricSpec half4(0.220916301, 0.220916301, 0.220916301, 1.0 - 0.220916301)
    #define unity_ColorSpaceLuminance half4(0.22, 0.707, 0.071, 0.0) // Legacy: alpha is set to 0.0 to specify gamma mode
    #else // Linear values
    #define unity_ColorSpaceGrey fixed4(0.214041144, 0.214041144, 0.214041144, 0.5)
    #define unity_ColorSpaceDouble fixed4(4.59479380, 4.59479380, 4.59479380, 2.0)
    #define unity_ColorSpaceDielectricSpec half4(0.04, 0.04, 0.04, 1.0 - 0.04) // standard dielectric reflectivity coef at incident angle (= 4%)
    #define unity_ColorSpaceLuminance half4(0.0396819152, 0.458021790, 0.00609653955, 1.0) // Legacy: alpha is set to 1.0 to specify linear mode
    #endif
    
    // -------------------------------------------------------------------
    //  helper functions and macros used in many standard shaders
    
    
    #if defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE) || defined (POINT) || defined (SPOT) || defined (POINT_NOATT) || defined (POINT_COOKIE)
    #define USING_LIGHT_MULTI_COMPILE
    #endif
    
    #if defined(SHADER_API_D3D11) || defined(SHADER_API_PSSL) || defined(SHADER_API_METAL) || defined(SHADER_API_GLCORE) || defined(SHADER_API_GLES3) || defined(SHADER_API_VULKAN) || defined(SHADER_API_SWITCH) // D3D11, D3D12, XB1, PS4, iOS, macOS, tvOS, glcore, gles3, webgl2.0, Switch
    // Real-support for depth-format cube shadow map.
    #define SHADOWS_CUBE_IN_DEPTH_TEX
    #endif
    
    #define SCALED_NORMAL v.normal
    
    
    // These constants must be kept in sync with RGBMRanges.h
    #define LIGHTMAP_RGBM_SCALE 5.0
    #define EMISSIVE_RGBM_SCALE 97.0
    
    struct  appdata_base {
        float4 vertex : POSITION;
        float3 normal : NORMAL;
        float4 texcoord : TEXCOORD0;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };
    
    struct  appdata_tan {
        float4 vertex : POSITION;
        float4 tangent : TANGENT;
        float3 normal : NORMAL;
        float4 texcoord : TEXCOORD0;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };
    
    struct  appdata_full {
        float4 vertex : POSITION;
        float4 tangent : TANGENT;
        float3 normal : NORMAL;
        float4 texcoord : TEXCOORD0;
        float4 texcoord1 : TEXCOORD1;
        float4 texcoord2 : TEXCOORD2;
        float4 texcoord3 : TEXCOORD3;
        fixed4 color : COLOR;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };
    
    // Legacy for compatibility with existing shaders
    inline bool IsGammaSpace()
    {
        #ifdef UNITY_COLORSPACE_GAMMA
            return true;
        #else
            return false;
        #endif
    }
    
    inline float GammaToLinearSpaceExact (float value)
    {
        if (value <= 0.04045F)
            return value / 12.92F;
        else if (value < 1.0F)
            return pow((value + 0.055F)/1.055F, 2.4F);
        else
            return pow(value, 2.2F);
    }
    
    inline half3 GammaToLinearSpace (half3 sRGB)
    {
        // Approximate version from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
        return sRGB * (sRGB * (sRGB * 0.305306011h + 0.682171111h) + 0.012522878h);
    
        // Precise version, useful for debugging.
        //return half3(GammaToLinearSpaceExact(sRGB.r), GammaToLinearSpaceExact(sRGB.g), GammaToLinearSpaceExact(sRGB.b));
    }
    
    inline float LinearToGammaSpaceExact (float value)
    {
        if (value <= 0.0F)
            return 0.0F;
        else if (value <= 0.0031308F)
            return 12.92F * value;
        else if (value < 1.0F)
            return 1.055F * pow(value, 0.4166667F) - 0.055F;
        else
            return pow(value, 0.45454545F);
    }
    
    inline half3 LinearToGammaSpace (half3 linRGB)
    {
        linRGB = max(linRGB, half3(0.h, 0.h, 0.h));
        // An almost-perfect approximation from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
        return max(1.055h * pow(linRGB, 0.416666667h) - 0.055h, 0.h);
    
        // Exact version, useful for debugging.
        //return half3(LinearToGammaSpaceExact(linRGB.r), LinearToGammaSpaceExact(linRGB.g), LinearToGammaSpaceExact(linRGB.b));
    }
    
    // Tranforms position from world to homogenous space
    inline float4 UnityWorldToClipPos( in float3 pos )
    {
        return mul(UNITY_MATRIX_VP, float4(pos, 1.0));
    }
    
    // Tranforms position from view to homogenous space
    inline float4 UnityViewToClipPos( in float3 pos )
    {
        return mul(UNITY_MATRIX_P, float4(pos, 1.0));
    }
    
    // Tranforms position from object to camera space
    inline float3 UnityObjectToViewPos( in float3 pos )
    {
        return mul(UNITY_MATRIX_V, mul(unity_ObjectToWorld, float4(pos, 1.0))).xyz;
    }
    inline float3 UnityObjectToViewPos(float4 pos) // overload for float4; avoids "implicit truncation" warning for existing shaders
    {
        return UnityObjectToViewPos(pos.xyz);
    }
    
    // Tranforms position from world to camera space
    inline float3 UnityWorldToViewPos( in float3 pos )
    {
        return mul(UNITY_MATRIX_V, float4(pos, 1.0)).xyz;
    }
    
    // Transforms direction from object to world space
    inline float3 UnityObjectToWorldDir( in float3 dir )
    {
        return normalize(mul((float3x3)unity_ObjectToWorld, dir));
    }
    
    // Transforms direction from world to object space
    inline float3 UnityWorldToObjectDir( in float3 dir )
    {
        return normalize(mul((float3x3)unity_WorldToObject, dir));
    }
    
    // Transforms normal from object to world space
    inline float3 UnityObjectToWorldNormal( in float3 norm )
    {
    #ifdef UNITY_ASSUME_UNIFORM_SCALING
        return UnityObjectToWorldDir(norm);
    #else
        // mul(IT_M, norm) => mul(norm, I_M) => {dot(norm, I_M.col0), dot(norm, I_M.col1), dot(norm, I_M.col2)}
        return normalize(mul(norm, (float3x3)unity_WorldToObject));
    #endif
    }
    
    // Computes world space light direction, from world space position
    inline float3 UnityWorldSpaceLightDir( in float3 worldPos )
    {
        #ifndef USING_LIGHT_MULTI_COMPILE
            return _WorldSpaceLightPos0.xyz - worldPos * _WorldSpaceLightPos0.w;
        #else
            #ifndef USING_DIRECTIONAL_LIGHT
            return _WorldSpaceLightPos0.xyz - worldPos;
            #else
            return _WorldSpaceLightPos0.xyz;
            #endif
        #endif
    }
    
    // Computes world space light direction, from object space position
    // *Legacy* Please use UnityWorldSpaceLightDir instead
    inline float3 WorldSpaceLightDir( in float4 localPos )
    {
        float3 worldPos = mul(unity_ObjectToWorld, localPos).xyz;
        return UnityWorldSpaceLightDir(worldPos);
    }
    
    // Computes object space light direction
    inline float3 ObjSpaceLightDir( in float4 v )
    {
        float3 objSpaceLightPos = mul(unity_WorldToObject, _WorldSpaceLightPos0).xyz;
        #ifndef USING_LIGHT_MULTI_COMPILE
            return objSpaceLightPos.xyz - v.xyz * _WorldSpaceLightPos0.w;
        #else
            #ifndef USING_DIRECTIONAL_LIGHT
            return objSpaceLightPos.xyz - v.xyz;
            #else
            return objSpaceLightPos.xyz;
            #endif
        #endif
    }
    
    // Computes world space view direction, from object space position
    inline float3 UnityWorldSpaceViewDir( in float3 worldPos )
    {
        return _WorldSpaceCameraPos.xyz - worldPos;
    }
    
    // Computes world space view direction, from object space position
    // *Legacy* Please use UnityWorldSpaceViewDir instead
    inline float3 WorldSpaceViewDir( in float4 localPos )
    {
        float3 worldPos = mul(unity_ObjectToWorld, localPos).xyz;
        return UnityWorldSpaceViewDir(worldPos);
    }
    
    // Computes object space view direction
    inline float3 ObjSpaceViewDir( in float4 v )
    {
        float3 objSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz;
        return objSpaceCameraPos - v.xyz;
    }
    
    // Declares 3x3 matrix 'rotation', filled with tangent space basis
    #define TANGENT_SPACE_ROTATION \
        float3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w; \
        float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal )
    
    
    
    // Used in ForwardBase pass: Calculates diffuse lighting from 4 point lights, with data packed in a special way.
    float3 Shade4PointLights (
        float4 lightPosX, float4 lightPosY, float4 lightPosZ,
        float3 lightColor0, float3 lightColor1, float3 lightColor2, float3 lightColor3,
        float4 lightAttenSq,
        float3 pos, float3 normal)
    {
        // to light vectors
        float4 toLightX = lightPosX - pos.x;
        float4 toLightY = lightPosY - pos.y;
        float4 toLightZ = lightPosZ - pos.z;
        // squared lengths
        float4 lengthSq = 0;
        lengthSq += toLightX * toLightX;
        lengthSq += toLightY * toLightY;
        lengthSq += toLightZ * toLightZ;
        // don't produce NaNs if some vertex position overlaps with the light
        lengthSq = max(lengthSq, 0.000001);
    
        // NdotL
        float4 ndotl = 0;
        ndotl += toLightX * normal.x;
        ndotl += toLightY * normal.y;
        ndotl += toLightZ * normal.z;
        // correct NdotL
        float4 corr = rsqrt(lengthSq);
        ndotl = max (float4(0,0,0,0), ndotl * corr);
        // attenuation
        float4 atten = 1.0 / (1.0 + lengthSq * lightAttenSq);
        float4 diff = ndotl * atten;
        // final color
        float3 col = 0;
        col += lightColor0 * diff.x;
        col += lightColor1 * diff.y;
        col += lightColor2 * diff.z;
        col += lightColor3 * diff.w;
        return col;
    }
    
    // Used in Vertex pass: Calculates diffuse lighting from lightCount lights. Specifying true to spotLight is more expensive
    // to calculate but lights are treated as spot lights otherwise they are treated as point lights.
    float3 ShadeVertexLightsFull (float4 vertex, float3 normal, int lightCount, bool spotLight)
    {
        float3 viewpos = UnityObjectToViewPos (vertex.xyz);
        float3 viewN = normalize (mul ((float3x3)UNITY_MATRIX_IT_MV, normal));
    
        float3 lightColor = UNITY_LIGHTMODEL_AMBIENT.xyz;
        for (int i = 0; i < lightCount; i++) {
            float3 toLight = unity_LightPosition[i].xyz - viewpos.xyz * unity_LightPosition[i].w;
            float lengthSq = dot(toLight, toLight);
    
            // don't produce NaNs if some vertex position overlaps with the light
            lengthSq = max(lengthSq, 0.000001);
    
            toLight *= rsqrt(lengthSq);
    
            float atten = 1.0 / (1.0 + lengthSq * unity_LightAtten[i].z);
            if (spotLight)
            {
                float rho = max (0, dot(toLight, unity_SpotDirection[i].xyz));
                float spotAtt = (rho - unity_LightAtten[i].x) * unity_LightAtten[i].y;
                atten *= saturate(spotAtt);
            }
    
            float diff = max (0, dot (viewN, toLight));
            lightColor += unity_LightColor[i].rgb * (diff * atten);
        }
        return lightColor;
    }
    
    float3 ShadeVertexLights (float4 vertex, float3 normal)
    {
        return ShadeVertexLightsFull (vertex, normal, 4, false);
    }
    
    // normal should be normalized, w=1.0
    half3 SHEvalLinearL0L1 (half4 normal)
    {
        half3 x;
    
        // Linear (L1) + constant (L0) polynomial terms
        x.r = dot(unity_SHAr,normal);
        x.g = dot(unity_SHAg,normal);
        x.b = dot(unity_SHAb,normal);
    
        return x;
    }
    
    // normal should be normalized, w=1.0
    half3 SHEvalLinearL2 (half4 normal)
    {
        half3 x1, x2;
        // 4 of the quadratic (L2) polynomials
        half4 vB = normal.xyzz * normal.yzzx;
        x1.r = dot(unity_SHBr,vB);
        x1.g = dot(unity_SHBg,vB);
        x1.b = dot(unity_SHBb,vB);
    
        // Final (5th) quadratic (L2) polynomial
        half vC = normal.x*normal.x - normal.y*normal.y;
        x2 = unity_SHC.rgb * vC;
    
        return x1 + x2;
    }
    
    // normal should be normalized, w=1.0
    // output in active color space
    half3 ShadeSH9 (half4 normal)
    {
        // Linear + constant polynomial terms
        half3 res = SHEvalLinearL0L1 (normal);
    
        // Quadratic polynomials
        res += SHEvalLinearL2 (normal);
    
    #   ifdef UNITY_COLORSPACE_GAMMA
            res = LinearToGammaSpace (res);
    #   endif
    
        return res;
    }
    
    // OBSOLETE: for backwards compatibility with 5.0
    half3 ShadeSH3Order(half4 normal)
    {
        // Quadratic polynomials
        half3 res = SHEvalLinearL2 (normal);
    
    #   ifdef UNITY_COLORSPACE_GAMMA
            res = LinearToGammaSpace (res);
    #   endif
    
        return res;
    }
    
    #if UNITY_LIGHT_PROBE_PROXY_VOLUME
    
    // normal should be normalized, w=1.0
    half3 SHEvalLinearL0L1_SampleProbeVolume (half4 normal, float3 worldPos)
    {
        const float transformToLocal = unity_ProbeVolumeParams.y;
        const float texelSizeX = unity_ProbeVolumeParams.z;
    
        //The SH coefficients textures and probe occlusion are packed into 1 atlas.
        //-------------------------
        //| ShR | ShG | ShB | Occ |
        //-------------------------
    
        float3 position = (transformToLocal == 1.0f) ? mul(unity_ProbeVolumeWorldToObject, float4(worldPos, 1.0)).xyz : worldPos;
        float3 texCoord = (position - unity_ProbeVolumeMin.xyz) * unity_ProbeVolumeSizeInv.xyz;
        texCoord.x = texCoord.x * 0.25f;
    
        // We need to compute proper X coordinate to sample.
        // Clamp the coordinate otherwize we'll have leaking between RGB coefficients
        float texCoordX = clamp(texCoord.x, 0.5f * texelSizeX, 0.25f - 0.5f * texelSizeX);
    
        // sampler state comes from SHr (all SH textures share the same sampler)
        texCoord.x = texCoordX;
        half4 SHAr = UNITY_SAMPLE_TEX3D_SAMPLER(unity_ProbeVolumeSH, unity_ProbeVolumeSH, texCoord);
    
        texCoord.x = texCoordX + 0.25f;
        half4 SHAg = UNITY_SAMPLE_TEX3D_SAMPLER(unity_ProbeVolumeSH, unity_ProbeVolumeSH, texCoord);
    
        texCoord.x = texCoordX + 0.5f;
        half4 SHAb = UNITY_SAMPLE_TEX3D_SAMPLER(unity_ProbeVolumeSH, unity_ProbeVolumeSH, texCoord);
    
        // Linear + constant polynomial terms
        half3 x1;
        x1.r = dot(SHAr, normal);
        x1.g = dot(SHAg, normal);
        x1.b = dot(SHAb, normal);
    
        return x1;
    }
    #endif
    
    // normal should be normalized, w=1.0
    half3 ShadeSH12Order (half4 normal)
    {
        // Linear + constant polynomial terms
        half3 res = SHEvalLinearL0L1 (normal);
    
    #   ifdef UNITY_COLORSPACE_GAMMA
            res = LinearToGammaSpace (res);
    #   endif
    
        return res;
    }
    
    // Transforms 2D UV by scale/bias property
    #define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
    
    // Deprecated. Used to transform 4D UV by a fixed function texture matrix. Now just returns the passed UV.
    #define TRANSFORM_UV(idx) v.texcoord.xy
    
    
    
    struct v2f_vertex_lit {
        float2 uv   : TEXCOORD0;
        fixed4 diff : COLOR0;
        fixed4 spec : COLOR1;
    };
    
    inline fixed4 VertexLight( v2f_vertex_lit i, sampler2D mainTex )
    {
        fixed4 texcol = tex2D( mainTex, i.uv );
        fixed4 c;
        c.xyz = ( texcol.xyz * i.diff.xyz + i.spec.xyz * texcol.a );
        c.w = texcol.w * i.diff.w;
        return c;
    }
    
    
    // Calculates UV offset for parallax bump mapping
    inline float2 ParallaxOffset( half h, half height, half3 viewDir )
    {
        h = h * height - height/2.0;
        float3 v = normalize(viewDir);
        v.z += 0.42;
        return h * (v.xy / v.z);
    }
    
    // Converts color to luminance (grayscale)
    inline half Luminance(half3 rgb)
    {
        return dot(rgb, unity_ColorSpaceLuminance.rgb);
    }
    
    // Convert rgb to luminance
    // with rgb in linear space with sRGB primaries and D65 white point
    half LinearRgbToLuminance(half3 linearRgb)
    {
        return dot(linearRgb, half3(0.2126729f,  0.7151522f, 0.0721750f));
    }
    
    half4 UnityEncodeRGBM (half3 color, float maxRGBM)
    {
        float kOneOverRGBMMaxRange = 1.0 / maxRGBM;
        const float kMinMultiplier = 2.0 * 1e-2;
    
        float3 rgb = color * kOneOverRGBMMaxRange;
        float alpha = max(max(rgb.r, rgb.g), max(rgb.b, kMinMultiplier));
        alpha = ceil(alpha * 255.0) / 255.0;
    
        // Division-by-zero warning from d3d9, so make compiler happy.
        alpha = max(alpha, kMinMultiplier);
    
        return half4(rgb / alpha, alpha);
    }
    
    // Decodes HDR textures
    // handles dLDR, RGBM formats
    inline half3 DecodeHDR (half4 data, half4 decodeInstructions)
    {
        // Take into account texture alpha if decodeInstructions.w is true(the alpha value affects the RGB channels)
        half alpha = decodeInstructions.w * (data.a - 1.0) + 1.0;
    
        // If Linear mode is not supported we can skip exponent part
        #if defined(UNITY_COLORSPACE_GAMMA)
            return (decodeInstructions.x * alpha) * data.rgb;
        #else
        #   if defined(UNITY_USE_NATIVE_HDR)
                return decodeInstructions.x * data.rgb; // Multiplier for future HDRI relative to absolute conversion.
        #   else
                return (decodeInstructions.x * pow(alpha, decodeInstructions.y)) * data.rgb;
        #   endif
        #endif
    }
    
    // Decodes HDR textures
    // handles dLDR, RGBM formats
    inline half3 DecodeLightmapRGBM (half4 data, half4 decodeInstructions)
    {
        // If Linear mode is not supported we can skip exponent part
        #if defined(UNITY_COLORSPACE_GAMMA)
        # if defined(UNITY_FORCE_LINEAR_READ_FOR_RGBM)
            return (decodeInstructions.x * data.a) * sqrt(data.rgb);
        # else
            return (decodeInstructions.x * data.a) * data.rgb;
        # endif
        #else
            return (decodeInstructions.x * pow(data.a, decodeInstructions.y)) * data.rgb;
        #endif
    }
    
    // Decodes doubleLDR encoded lightmaps.
    inline half3 DecodeLightmapDoubleLDR( fixed4 color, half4 decodeInstructions)
    {
        // decodeInstructions.x contains 2.0 when gamma color space is used or pow(2.0, 2.2) = 4.59 when linear color space is used on mobile platforms
        return decodeInstructions.x * color.rgb;
    }
    
    inline half3 DecodeLightmap( fixed4 color, half4 decodeInstructions)
    {
    #if defined(UNITY_LIGHTMAP_DLDR_ENCODING)
        return DecodeLightmapDoubleLDR(color, decodeInstructions);
    #elif defined(UNITY_LIGHTMAP_RGBM_ENCODING)
        return DecodeLightmapRGBM(color, decodeInstructions);
    #else //defined(UNITY_LIGHTMAP_FULL_HDR)
        return color.rgb;
    #endif
    }
    
    half4 unity_Lightmap_HDR;
    
    inline half3 DecodeLightmap( fixed4 color )
    {
        return DecodeLightmap( color, unity_Lightmap_HDR );
    }
    
    half4 unity_DynamicLightmap_HDR;
    
    // Decodes Enlighten RGBM encoded lightmaps
    // NOTE: Enlighten dynamic texture RGBM format is _different_ from standard Unity HDR textures
    // (such as Baked Lightmaps, Reflection Probes and IBL images)
    // Instead Enlighten provides RGBM texture in _Linear_ color space with _different_ exponent.
    // WARNING: 3 pow operations, might be very expensive for mobiles!
    inline half3 DecodeRealtimeLightmap( fixed4 color )
    {
        //@TODO: Temporary until Geomerics gives us an API to convert lightmaps to RGBM in gamma space on the enlighten thread before we upload the textures.
    #if defined(UNITY_FORCE_LINEAR_READ_FOR_RGBM)
        return pow ((unity_DynamicLightmap_HDR.x * color.a) * sqrt(color.rgb), unity_DynamicLightmap_HDR.y);
    #else
        return pow ((unity_DynamicLightmap_HDR.x * color.a) * color.rgb, unity_DynamicLightmap_HDR.y);
    #endif
    }
    
    inline half3 DecodeDirectionalLightmap (half3 color, fixed4 dirTex, half3 normalWorld)
    {
        // In directional (non-specular) mode Enlighten bakes dominant light direction
        // in a way, that using it for half Lambert and then dividing by a "rebalancing coefficient"
        // gives a result close to plain diffuse response lightmaps, but normalmapped.
    
        // Note that dir is not unit length on purpose. Its length is "directionality", like
        // for the directional specular lightmaps.
    
        half halfLambert = dot(normalWorld, dirTex.xyz - 0.5) + 0.5;
    
        return color * halfLambert / max(1e-4h, dirTex.w);
    }
    
    // Encoding/decoding [0..1) floats into 8 bit/channel RGBA. Note that 1.0 will not be encoded properly.
    inline float4 EncodeFloatRGBA( float v )
    {
        float4 kEncodeMul = float4(1.0, 255.0, 65025.0, 16581375.0);
        float kEncodeBit = 1.0/255.0;
        float4 enc = kEncodeMul * v;
        enc = frac (enc);
        enc -= enc.yzww * kEncodeBit;
        return enc;
    }
    inline float DecodeFloatRGBA( float4 enc )
    {
        float4 kDecodeDot = float4(1.0, 1/255.0, 1/65025.0, 1/16581375.0);
        return dot( enc, kDecodeDot );
    }
    
    // Encoding/decoding [0..1) floats into 8 bit/channel RG. Note that 1.0 will not be encoded properly.
    inline float2 EncodeFloatRG( float v )
    {
        float2 kEncodeMul = float2(1.0, 255.0);
        float kEncodeBit = 1.0/255.0;
        float2 enc = kEncodeMul * v;
        enc = frac (enc);
        enc.x -= enc.y * kEncodeBit;
        return enc;
    }
    inline float DecodeFloatRG( float2 enc )
    {
        float2 kDecodeDot = float2(1.0, 1/255.0);
        return dot( enc, kDecodeDot );
    }
    
    
    // Encoding/decoding view space normals into 2D 0..1 vector
    inline float2 EncodeViewNormalStereo( float3 n )
    {
        float kScale = 1.7777;
        float2 enc;
        enc = n.xy / (n.z+1);
        enc /= kScale;
        enc = enc*0.5+0.5;
        return enc;
    }
    inline float3 DecodeViewNormalStereo( float4 enc4 )
    {
        float kScale = 1.7777;
        float3 nn = enc4.xyz*float3(2*kScale,2*kScale,0) + float3(-kScale,-kScale,1);
        float g = 2.0 / dot(nn.xyz,nn.xyz);
        float3 n;
        n.xy = g*nn.xy;
        n.z = g-1;
        return n;
    }
    
    inline float4 EncodeDepthNormal( float depth, float3 normal )
    {
        float4 enc;
        enc.xy = EncodeViewNormalStereo (normal);
        enc.zw = EncodeFloatRG (depth);
        return enc;
    }
    
    inline void DecodeDepthNormal( float4 enc, out float depth, out float3 normal )
    {
        depth = DecodeFloatRG (enc.zw);
        normal = DecodeViewNormalStereo (enc);
    }
    
    inline fixed3 UnpackNormalDXT5nm (fixed4 packednormal)
    {
        fixed3 normal;
        normal.xy = packednormal.wy * 2 - 1;
        normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
        return normal;
    }
    
    // Unpack normal as DXT5nm (1, y, 1, x) or BC5 (x, y, 0, 1)
    // Note neutral texture like "bump" is (0, 0, 1, 1) to work with both plain RGB normal and DXT5nm/BC5
    fixed3 UnpackNormalmapRGorAG(fixed4 packednormal)
    {
        // This do the trick
       packednormal.x *= packednormal.w;
    
        fixed3 normal;
        normal.xy = packednormal.xy * 2 - 1;
        normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
        return normal;
    }
    inline fixed3 UnpackNormal(fixed4 packednormal)
    {
    #if defined(UNITY_NO_DXT5nm)
        return packednormal.xyz * 2 - 1;
    #else
        return UnpackNormalmapRGorAG(packednormal);
    #endif
    }
    
    fixed3 UnpackNormalWithScale(fixed4 packednormal, float scale)
    {
    #ifndef UNITY_NO_DXT5nm
        // Unpack normal as DXT5nm (1, y, 1, x) or BC5 (x, y, 0, 1)
        // Note neutral texture like "bump" is (0, 0, 1, 1) to work with both plain RGB normal and DXT5nm/BC5
        packednormal.x *= packednormal.w;
    #endif
        fixed3 normal;
        normal.xy = (packednormal.xy * 2 - 1) * scale;
        normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
        return normal;
    }
    
    // Z buffer to linear 0..1 depth
    inline float Linear01Depth( float z )
    {
        return 1.0 / (_ZBufferParams.x * z + _ZBufferParams.y);
    }
    // Z buffer to linear depth
    inline float LinearEyeDepth( float z )
    {
        return 1.0 / (_ZBufferParams.z * z + _ZBufferParams.w);
    }
    
    
    inline float2 UnityStereoScreenSpaceUVAdjustInternal(float2 uv, float4 scaleAndOffset)
    {
        return uv.xy * scaleAndOffset.xy + scaleAndOffset.zw;
    }
    
    inline float4 UnityStereoScreenSpaceUVAdjustInternal(float4 uv, float4 scaleAndOffset)
    {
        return float4(UnityStereoScreenSpaceUVAdjustInternal(uv.xy, scaleAndOffset), UnityStereoScreenSpaceUVAdjustInternal(uv.zw, scaleAndOffset));
    }
    
    #define UnityStereoScreenSpaceUVAdjust(x, y) UnityStereoScreenSpaceUVAdjustInternal(x, y)
    
    #if defined(UNITY_SINGLE_PASS_STEREO)
    float2 TransformStereoScreenSpaceTex(float2 uv, float w)
    {
        float4 scaleOffset = unity_StereoScaleOffset[unity_StereoEyeIndex];
        return uv.xy * scaleOffset.xy + scaleOffset.zw * w;
    }
    
    inline float2 UnityStereoTransformScreenSpaceTex(float2 uv)
    {
        return TransformStereoScreenSpaceTex(saturate(uv), 1.0);
    }
    
    inline float4 UnityStereoTransformScreenSpaceTex(float4 uv)
    {
        return float4(UnityStereoTransformScreenSpaceTex(uv.xy), UnityStereoTransformScreenSpaceTex(uv.zw));
    }
    inline float2 UnityStereoClamp(float2 uv, float4 scaleAndOffset)
    {
        return float2(clamp(uv.x, scaleAndOffset.z, scaleAndOffset.z + scaleAndOffset.x), uv.y);
    }
    #else
    #define TransformStereoScreenSpaceTex(uv, w) uv
    #define UnityStereoTransformScreenSpaceTex(uv) uv
    #define UnityStereoClamp(uv, scaleAndOffset) uv
    #endif
    
    // Depth render texture helpers
    #define DECODE_EYEDEPTH(i) LinearEyeDepth(i)
    #define COMPUTE_EYEDEPTH(o) o = -UnityObjectToViewPos( v.vertex ).z
    #define COMPUTE_DEPTH_01 -(UnityObjectToViewPos( v.vertex ).z * _ProjectionParams.w)
    #define COMPUTE_VIEW_NORMAL normalize(mul((float3x3)UNITY_MATRIX_IT_MV, v.normal))
    
    // Helpers used in image effects. Most image effects use the same
    // minimal vertex shader (vert_img).
    
    struct appdata_img
    {
        float4 vertex : POSITION;
        half2 texcoord : TEXCOORD0;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };
    
    struct v2f_img
    {
        float4 pos : SV_POSITION;
        half2 uv : TEXCOORD0;
        UNITY_VERTEX_INPUT_INSTANCE_ID
        UNITY_VERTEX_OUTPUT_STEREO
    };
    
    float2 MultiplyUV (float4x4 mat, float2 inUV) {
        float4 temp = float4 (inUV.x, inUV.y, 0, 0);
        temp = mul (mat, temp);
        return temp.xy;
    }
    
    v2f_img vert_img( appdata_img v )
    {
        v2f_img o;
        UNITY_INITIALIZE_OUTPUT(v2f_img, o);
        UNITY_SETUP_INSTANCE_ID(v);
        UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    
        o.pos = UnityObjectToClipPos (v.vertex);
        o.uv = v.texcoord;
        return o;
    }
    
    // Projected screen position helpers
    #define V2F_SCREEN_TYPE float4
    
    inline float4 ComputeNonStereoScreenPos(float4 pos) {
        float4 o = pos * 0.5f;
        o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w;
        o.zw = pos.zw;
        return o;
    }
    
    inline float4 ComputeScreenPos(float4 pos) {
        float4 o = ComputeNonStereoScreenPos(pos);
    #if defined(UNITY_SINGLE_PASS_STEREO)
        o.xy = TransformStereoScreenSpaceTex(o.xy, pos.w);
    #endif
        return o;
    }
    
    inline float4 ComputeGrabScreenPos (float4 pos) {
        #if UNITY_UV_STARTS_AT_TOP
        float scale = -1.0;
        #else
        float scale = 1.0;
        #endif
        float4 o = pos * 0.5f;
        o.xy = float2(o.x, o.y*scale) + o.w;
    #ifdef UNITY_SINGLE_PASS_STEREO
        o.xy = TransformStereoScreenSpaceTex(o.xy, pos.w);
    #endif
        o.zw = pos.zw;
        return o;
    }
    
    // snaps post-transformed position to screen pixels
    inline float4 UnityPixelSnap (float4 pos)
    {
        float2 hpc = _ScreenParams.xy * 0.5f;
    #if  SHADER_API_PSSL
    // sdk 4.5 splits round into v_floor_f32(x+0.5) ... sdk 5.0 uses v_rndne_f32, for compatabilty we use the 4.5 version
        float2 temp = ((pos.xy / pos.w) * hpc) + float2(0.5f,0.5f);
        float2 pixelPos = float2(__v_floor_f32(temp.x), __v_floor_f32(temp.y));
    #else
        float2 pixelPos = round ((pos.xy / pos.w) * hpc);
    #endif
        pos.xy = pixelPos / hpc * pos.w;
        return pos;
    }
    
    inline float2 TransformViewToProjection (float2 v) {
        return mul((float2x2)UNITY_MATRIX_P, v);
    }
    
    inline float3 TransformViewToProjection (float3 v) {
        return mul((float3x3)UNITY_MATRIX_P, v);
    }
    
    // Shadow caster pass helpers
    
    float4 UnityEncodeCubeShadowDepth (float z)
    {
        #ifdef UNITY_USE_RGBA_FOR_POINT_SHADOWS
        return EncodeFloatRGBA (min(z, 0.999));
        #else
        return z;
        #endif
    }
    
    float UnityDecodeCubeShadowDepth (float4 vals)
    {
        #ifdef UNITY_USE_RGBA_FOR_POINT_SHADOWS
        return DecodeFloatRGBA (vals);
        #else
        return vals.r;
        #endif
    }
    
    
    float4 UnityClipSpaceShadowCasterPos(float4 vertex, float3 normal)
    {
        float4 wPos = mul(unity_ObjectToWorld, vertex);
    
        if (unity_LightShadowBias.z != 0.0)
        {
            float3 wNormal = UnityObjectToWorldNormal(normal);
            float3 wLight = normalize(UnityWorldSpaceLightDir(wPos.xyz));
    
            // apply normal offset bias (inset position along the normal)
            // bias needs to be scaled by sine between normal and light direction
            // (http://the-witness.net/news/2013/09/shadow-mapping-summary-part-1/)
            //
            // unity_LightShadowBias.z contains user-specified normal offset amount
            // scaled by world space texel size.
    
            float shadowCos = dot(wNormal, wLight);
            float shadowSine = sqrt(1-shadowCos*shadowCos);
            float normalBias = unity_LightShadowBias.z * shadowSine;
    
            wPos.xyz -= wNormal * normalBias;
        }
    
        return mul(UNITY_MATRIX_VP, wPos);
    }
    // Legacy, not used anymore; kept around to not break existing user shaders
    float4 UnityClipSpaceShadowCasterPos(float3 vertex, float3 normal)
    {
        return UnityClipSpaceShadowCasterPos(float4(vertex, 1), normal);
    }
    
    
    float4 UnityApplyLinearShadowBias(float4 clipPos)
    
    {
        // For point lights that support depth cube map, the bias is applied in the fragment shader sampling the shadow map.
        // This is because the legacy behaviour for point light shadow map cannot be implemented by offseting the vertex position
        // in the vertex shader generating the shadow map.
    #if !(defined(SHADOWS_CUBE) && defined(SHADOWS_CUBE_IN_DEPTH_TEX))
        #if defined(UNITY_REVERSED_Z)
            // We use max/min instead of clamp to ensure proper handling of the rare case
            // where both numerator and denominator are zero and the fraction becomes NaN.
            clipPos.z += max(-1, min(unity_LightShadowBias.x / clipPos.w, 0));
        #else
            clipPos.z += saturate(unity_LightShadowBias.x/clipPos.w);
        #endif
    #endif
    
    #if defined(UNITY_REVERSED_Z)
        float clamped = min(clipPos.z, clipPos.w*UNITY_NEAR_CLIP_VALUE);
    #else
        float clamped = max(clipPos.z, clipPos.w*UNITY_NEAR_CLIP_VALUE);
    #endif
        clipPos.z = lerp(clipPos.z, clamped, unity_LightShadowBias.y);
        return clipPos;
    }
    
    
    #if defined(SHADOWS_CUBE) && !defined(SHADOWS_CUBE_IN_DEPTH_TEX)
        // Rendering into point light (cubemap) shadows
        #define V2F_SHADOW_CASTER_NOPOS float3 vec : TEXCOORD0;
        #define TRANSFER_SHADOW_CASTER_NOPOS_LEGACY(o,opos) o.vec = mul(unity_ObjectToWorld, v.vertex).xyz - _LightPositionRange.xyz; opos = UnityObjectToClipPos(v.vertex);
        #define TRANSFER_SHADOW_CASTER_NOPOS(o,opos) o.vec = mul(unity_ObjectToWorld, v.vertex).xyz - _LightPositionRange.xyz; opos = UnityObjectToClipPos(v.vertex);
        #define SHADOW_CASTER_FRAGMENT(i) return UnityEncodeCubeShadowDepth ((length(i.vec) + unity_LightShadowBias.x) * _LightPositionRange.w);
    
    #else
        // Rendering into directional or spot light shadows
        #define V2F_SHADOW_CASTER_NOPOS
        // Let embedding code know that V2F_SHADOW_CASTER_NOPOS is empty; so that it can workaround
        // empty structs that could possibly be produced.
        #define V2F_SHADOW_CASTER_NOPOS_IS_EMPTY
        #define TRANSFER_SHADOW_CASTER_NOPOS_LEGACY(o,opos) \
            opos = UnityObjectToClipPos(v.vertex.xyz); \
            opos = UnityApplyLinearShadowBias(opos);
        #define TRANSFER_SHADOW_CASTER_NOPOS(o,opos) \
            opos = UnityClipSpaceShadowCasterPos(v.vertex, v.normal); \
            opos = UnityApplyLinearShadowBias(opos);
        #define SHADOW_CASTER_FRAGMENT(i) return 0;
    #endif
    
    // Declare all data needed for shadow caster pass output (any shadow directions/depths/distances as needed),
    // plus clip space position.
    #define V2F_SHADOW_CASTER V2F_SHADOW_CASTER_NOPOS UNITY_POSITION(pos)
    
    // Vertex shader part, with support for normal offset shadows. Requires
    // position and normal to be present in the vertex input.
    #define TRANSFER_SHADOW_CASTER_NORMALOFFSET(o) TRANSFER_SHADOW_CASTER_NOPOS(o,o.pos)
    
    // Vertex shader part, legacy. No support for normal offset shadows - because
    // that would require vertex normals, which might not be present in user-written shaders.
    #define TRANSFER_SHADOW_CASTER(o) TRANSFER_SHADOW_CASTER_NOPOS_LEGACY(o,o.pos)
    
    
    // ------------------------------------------------------------------
    //  Alpha helper
    
    #define UNITY_OPAQUE_ALPHA(outputAlpha) outputAlpha = 1.0
    
    
    // ------------------------------------------------------------------
    //  Fog helpers
    //
    //  multi_compile_fog Will compile fog variants.
    //  UNITY_FOG_COORDS(texcoordindex) Declares the fog data interpolator.
    //  UNITY_TRANSFER_FOG(outputStruct,clipspacePos) Outputs fog data from the vertex shader.
    //  UNITY_APPLY_FOG(fogData,col) Applies fog to color "col". Automatically applies black fog when in forward-additive pass.
    //  Can also use UNITY_APPLY_FOG_COLOR to supply your own fog color.
    
    // In case someone by accident tries to compile fog code in one of the g-buffer or shadow passes:
    // treat it as fog is off.
    #if defined(UNITY_PASS_PREPASSBASE) || defined(UNITY_PASS_DEFERRED) || defined(UNITY_PASS_SHADOWCASTER)
    #undef FOG_LINEAR
    #undef FOG_EXP
    #undef FOG_EXP2
    #endif
    
    #if defined(UNITY_REVERSED_Z)
        #if UNITY_REVERSED_Z == 1
            //D3d with reversed Z => z clip range is [near, 0] -> remapping to [0, far]
            //max is required to protect ourselves from near plane not being correct/meaningfull in case of oblique matrices.
            #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(((1.0-(coord)/_ProjectionParams.y)*_ProjectionParams.z),0)
        #else
            //GL with reversed z => z clip range is [near, -far] -> should remap in theory but dont do it in practice to save some perf (range is close enough)
            #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(-(coord), 0)
        #endif
    #elif UNITY_UV_STARTS_AT_TOP
        //D3d without reversed z => z clip range is [0, far] -> nothing to do
        #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord)
    #else
        //Opengl => z clip range is [-near, far] -> should remap in theory but dont do it in practice to save some perf (range is close enough)
        #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord)
    #endif
    
    #if defined(FOG_LINEAR)
        // factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))
        #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = (coord) * unity_FogParams.z + unity_FogParams.w
    #elif defined(FOG_EXP)
        // factor = exp(-density*z)
        #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = unity_FogParams.y * (coord); unityFogFactor = exp2(-unityFogFactor)
    #elif defined(FOG_EXP2)
        // factor = exp(-(density*z)^2)
        #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = unity_FogParams.x * (coord); unityFogFactor = exp2(-unityFogFactor*unityFogFactor)
    #else
        #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = 0.0
    #endif
    
    #define UNITY_CALC_FOG_FACTOR(coord) UNITY_CALC_FOG_FACTOR_RAW(UNITY_Z_0_FAR_FROM_CLIPSPACE(coord))
    
    #define UNITY_FOG_COORDS_PACKED(idx, vectype) vectype fogCoord : TEXCOORD##idx;
    
    #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
        #define UNITY_FOG_COORDS(idx) UNITY_FOG_COORDS_PACKED(idx, float1)
    
        #if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE)
            // mobile or SM2.0: calculate fog factor per-vertex
            #define UNITY_TRANSFER_FOG(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.fogCoord.x = unityFogFactor
            #define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.tSpace1.y = tangentSign; o.tSpace2.y = unityFogFactor
            #define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.worldPos.w = unityFogFactor
            #define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.eyeVec.w = unityFogFactor
        #else
            // SM3.0 and PC/console: calculate fog distance per-vertex, and fog factor per-pixel
            #define UNITY_TRANSFER_FOG(o,outpos) o.fogCoord.x = (outpos).z
            #define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos) o.tSpace2.y = (outpos).z
            #define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos) o.worldPos.w = (outpos).z
            #define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos) o.eyeVec.w = (outpos).z
        #endif
    #else
        #define UNITY_FOG_COORDS(idx)
        #define UNITY_TRANSFER_FOG(o,outpos)
        #define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos)
        #define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos)
        #define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos)
    #endif
    
    #define UNITY_FOG_LERP_COLOR(col,fogCol,fogFac) col.rgb = lerp((fogCol).rgb, (col).rgb, saturate(fogFac))
    
    
    #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
        #if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE)
            // mobile or SM2.0: fog factor was already calculated per-vertex, so just lerp the color
            #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) UNITY_FOG_LERP_COLOR(col,fogCol,(coord).x)
        #else
            // SM3.0 and PC/console: calculate fog factor and lerp fog color
            #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) UNITY_CALC_FOG_FACTOR((coord).x); UNITY_FOG_LERP_COLOR(col,fogCol,unityFogFactor)
        #endif
        #define UNITY_EXTRACT_FOG(name) float _unity_fogCoord = name.fogCoord
        #define UNITY_EXTRACT_FOG_FROM_TSPACE(name) float _unity_fogCoord = name.tSpace2.y
        #define UNITY_EXTRACT_FOG_FROM_WORLD_POS(name) float _unity_fogCoord = name.worldPos.w
        #define UNITY_EXTRACT_FOG_FROM_EYE_VEC(name) float _unity_fogCoord = name.eyeVec.w
    #else
        #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol)
        #define UNITY_EXTRACT_FOG(name)
        #define UNITY_EXTRACT_FOG_FROM_TSPACE(name)
        #define UNITY_EXTRACT_FOG_FROM_WORLD_POS(name)
        #define UNITY_EXTRACT_FOG_FROM_EYE_VEC(name)
    #endif
    
    #ifdef UNITY_PASS_FORWARDADD
        #define UNITY_APPLY_FOG(coord,col) UNITY_APPLY_FOG_COLOR(coord,col,fixed4(0,0,0,0))
    #else
        #define UNITY_APPLY_FOG(coord,col) UNITY_APPLY_FOG_COLOR(coord,col,unity_FogColor)
    #endif
    
    // ------------------------------------------------------------------
    //  TBN helpers
    #define UNITY_EXTRACT_TBN_0(name) fixed3 _unity_tbn_0 = name.tSpace0.xyz
    #define UNITY_EXTRACT_TBN_1(name) fixed3 _unity_tbn_1 = name.tSpace1.xyz
    #define UNITY_EXTRACT_TBN_2(name) fixed3 _unity_tbn_2 = name.tSpace2.xyz
    
    #define UNITY_EXTRACT_TBN(name) UNITY_EXTRACT_TBN_0(name); UNITY_EXTRACT_TBN_1(name); UNITY_EXTRACT_TBN_2(name)
    
    #define UNITY_EXTRACT_TBN_T(name) fixed3 _unity_tangent = fixed3(name.tSpace0.x, name.tSpace1.x, name.tSpace2.x)
    #define UNITY_EXTRACT_TBN_N(name) fixed3 _unity_normal = fixed3(name.tSpace0.z, name.tSpace1.z, name.tSpace2.z)
    #define UNITY_EXTRACT_TBN_B(name) fixed3 _unity_binormal = cross(_unity_normal, _unity_tangent)
    #define UNITY_CORRECT_TBN_B_SIGN(name) _unity_binormal *= name.tSpace1.y;
    #define UNITY_RECONSTRUCT_TBN_0 fixed3 _unity_tbn_0 = fixed3(_unity_tangent.x, _unity_binormal.x, _unity_normal.x)
    #define UNITY_RECONSTRUCT_TBN_1 fixed3 _unity_tbn_1 = fixed3(_unity_tangent.y, _unity_binormal.y, _unity_normal.y)
    #define UNITY_RECONSTRUCT_TBN_2 fixed3 _unity_tbn_2 = fixed3(_unity_tangent.z, _unity_binormal.z, _unity_normal.z)
    
    #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
        #define UNITY_RECONSTRUCT_TBN(name) UNITY_EXTRACT_TBN_T(name); UNITY_EXTRACT_TBN_N(name); UNITY_EXTRACT_TBN_B(name); UNITY_CORRECT_TBN_B_SIGN(name); UNITY_RECONSTRUCT_TBN_0; UNITY_RECONSTRUCT_TBN_1; UNITY_RECONSTRUCT_TBN_2
    #else
        #define UNITY_RECONSTRUCT_TBN(name) UNITY_EXTRACT_TBN(name)
    #endif
    
    //  LOD cross fade helpers
    // keep all the old macros
    #define UNITY_DITHER_CROSSFADE_COORDS
    #define UNITY_DITHER_CROSSFADE_COORDS_IDX(idx)
    #define UNITY_TRANSFER_DITHER_CROSSFADE(o,v)
    #define UNITY_TRANSFER_DITHER_CROSSFADE_HPOS(o,hpos)
    
    #ifdef LOD_FADE_CROSSFADE
        #define UNITY_APPLY_DITHER_CROSSFADE(vpos)  UnityApplyDitherCrossFade(vpos)
        sampler2D _DitherMaskLOD2D;
        void UnityApplyDitherCrossFade(float2 vpos)
        {
            vpos /= 4; // the dither mask texture is 4x4
            vpos.y = frac(vpos.y) * 0.0625 /* 1/16 */ + unity_LODFade.y; // quantized lod fade by 16 levels
            clip(tex2D(_DitherMaskLOD2D, vpos).a - 0.5);
        }
    #else
        #define UNITY_APPLY_DITHER_CROSSFADE(vpos)
    #endif
    
    
    // ------------------------------------------------------------------
    //  Deprecated things: these aren't used; kept here
    //  just so that various existing shaders still compile, more or less.
    
    
    // Note: deprecated shadow collector pass helpers
    #ifdef SHADOW_COLLECTOR_PASS
    
    #if !defined(SHADOWMAPSAMPLER_DEFINED)
    UNITY_DECLARE_SHADOWMAP(_ShadowMapTexture);
    #endif
    
    // Note: V2F_SHADOW_COLLECTOR and TRANSFER_SHADOW_COLLECTOR are deprecated
    #define V2F_SHADOW_COLLECTOR float4 pos : SV_POSITION; float3 _ShadowCoord0 : TEXCOORD0; float3 _ShadowCoord1 : TEXCOORD1; float3 _ShadowCoord2 : TEXCOORD2; float3 _ShadowCoord3 : TEXCOORD3; float4 _WorldPosViewZ : TEXCOORD4
    #define TRANSFER_SHADOW_COLLECTOR(o)    \
        o.pos = UnityObjectToClipPos(v.vertex); \
        float4 wpos = mul(unity_ObjectToWorld, v.vertex); \
        o._WorldPosViewZ.xyz = wpos; \
        o._WorldPosViewZ.w = -UnityObjectToViewPos(v.vertex).z; \
        o._ShadowCoord0 = mul(unity_WorldToShadow[0], wpos).xyz; \
        o._ShadowCoord1 = mul(unity_WorldToShadow[1], wpos).xyz; \
        o._ShadowCoord2 = mul(unity_WorldToShadow[2], wpos).xyz; \
        o._ShadowCoord3 = mul(unity_WorldToShadow[3], wpos).xyz;
    
    // Note: SAMPLE_SHADOW_COLLECTOR_SHADOW is deprecated
    #define SAMPLE_SHADOW_COLLECTOR_SHADOW(coord) \
        half shadow = UNITY_SAMPLE_SHADOW(_ShadowMapTexture,coord); \
        shadow = _LightShadowData.r + shadow * (1-_LightShadowData.r);
    
    // Note: COMPUTE_SHADOW_COLLECTOR_SHADOW is deprecated
    #define COMPUTE_SHADOW_COLLECTOR_SHADOW(i, weights, shadowFade) \
        float4 coord = float4(i._ShadowCoord0 * weights[0] + i._ShadowCoord1 * weights[1] + i._ShadowCoord2 * weights[2] + i._ShadowCoord3 * weights[3], 1); \
        SAMPLE_SHADOW_COLLECTOR_SHADOW(coord) \
        float4 res; \
        res.x = saturate(shadow + shadowFade); \
        res.y = 1.0; \
        res.zw = EncodeFloatRG (1 - i._WorldPosViewZ.w * _ProjectionParams.w); \
        return res;
    
    // Note: deprecated
    #if defined (SHADOWS_SPLIT_SPHERES)
    #define SHADOW_COLLECTOR_FRAGMENT(i) \
        float3 fromCenter0 = i._WorldPosViewZ.xyz - unity_ShadowSplitSpheres[0].xyz; \
        float3 fromCenter1 = i._WorldPosViewZ.xyz - unity_ShadowSplitSpheres[1].xyz; \
        float3 fromCenter2 = i._WorldPosViewZ.xyz - unity_ShadowSplitSpheres[2].xyz; \
        float3 fromCenter3 = i._WorldPosViewZ.xyz - unity_ShadowSplitSpheres[3].xyz; \
        float4 distances2 = float4(dot(fromCenter0,fromCenter0), dot(fromCenter1,fromCenter1), dot(fromCenter2,fromCenter2), dot(fromCenter3,fromCenter3)); \
        float4 cascadeWeights = float4(distances2 < unity_ShadowSplitSqRadii); \
        cascadeWeights.yzw = saturate(cascadeWeights.yzw - cascadeWeights.xyz); \
        float sphereDist = distance(i._WorldPosViewZ.xyz, unity_ShadowFadeCenterAndType.xyz); \
        float shadowFade = saturate(sphereDist * _LightShadowData.z + _LightShadowData.w); \
        COMPUTE_SHADOW_COLLECTOR_SHADOW(i, cascadeWeights, shadowFade)
    #else
    #define SHADOW_COLLECTOR_FRAGMENT(i) \
        float4 viewZ = i._WorldPosViewZ.w; \
        float4 zNear = float4( viewZ >= _LightSplitsNear ); \
        float4 zFar = float4( viewZ < _LightSplitsFar ); \
        float4 cascadeWeights = zNear * zFar; \
        float shadowFade = saturate(i._WorldPosViewZ.w * _LightShadowData.z + _LightShadowData.w); \
        COMPUTE_SHADOW_COLLECTOR_SHADOW(i, cascadeWeights, shadowFade)
    #endif
    
    #endif // #ifdef SHADOW_COLLECTOR_PASS
    
    
    // Legacy; used to do something on platforms that had to emulate depth textures manually. Now all platforms have native depth textures.
    #define UNITY_TRANSFER_DEPTH(oo)
    // Legacy; used to do something on platforms that had to emulate depth textures manually. Now all platforms have native depth textures.
    #define UNITY_OUTPUT_DEPTH(i) return 0
    
    
    
    #define API_HAS_GUARANTEED_R16_SUPPORT !(SHADER_API_VULKAN || SHADER_API_GLES || SHADER_API_GLES3)
    
    float4 PackHeightmap(float height)
    {
        #if (API_HAS_GUARANTEED_R16_SUPPORT)
            return height;
        #else
            uint a = (uint)(65535.0f * height);
            return float4((a >> 0) & 0xFF, (a >> 8) & 0xFF, 0, 0) / 255.0f;
        #endif
    }
    
    float UnpackHeightmap(float4 height)
    {
        #if (API_HAS_GUARANTEED_R16_SUPPORT)
            return height.r;
        #else
            return (height.r + height.g * 256.0f) / 257.0f; // (255.0f * height.r + 255.0f * 256.0f * height.g) / 65535.0f
        #endif
    }
    
    #endif // UNITY_CG_INCLUDED