#ifndef WATER_STANDARD_OUTPUT
#define WATER_STANDARD_OUTPUT
#include "../Sky&Fog/VolumetricFogForObject.hlsl"
#include "Water_Standard_Input.hlsl"
#define pi 3.14
float2 Panner(float2 uv, float direction, float speed, float2 offset, float tiling)
{
    direction = direction * 2 - 1;
    float2 dir = normalize(float2(cos(pi * direction), sin(pi * direction)));
    return  (dir * _Time.y * speed) + offset + (uv * tiling);
}
float2 GradientNoiseDir(float2 p)
{   
    p = p % 289;
    float x = (34 * p.x + 1) * p.x % 289 + p.y;
    x = (34 * x + 1) * x % 289;
    x = frac(x / 41) * 2 - 1;
    return normalize(float2(x - floor(x + 0.5), abs(x) - 0.5));
}
float GradientNoise(float2 p)
{
    float2 ip = floor(p);
    float2 fp = frac(p);
    float d00 = dot(GradientNoiseDir(ip), fp);
    float d01 = dot(GradientNoiseDir(ip + float2(0, 1)), fp - float2(0, 1));
    float d10 = dot(GradientNoiseDir(ip + float2(1, 0)), fp - float2(1, 0));
    float d11 = dot(GradientNoiseDir(ip + float2(1, 1)), fp - float2(1, 1));
    fp = fp * fp * fp * (fp * (fp * 6 - 15) + 10);
    return lerp(lerp(d00, d01, fp.y), lerp(d10, d11, fp.y), fp.x) + 0.5;
}
float2 RefractUV_float(float2 uv, float3 parameters)
{
    float speed = parameters.x;
    float scale = parameters.y;
    float strength = parameters.z;

    float2 PanningUV = Panner(uv, 1, speed, 0, 1/scale);
    float Noise = GradientNoise(PanningUV);
    float2 RemappedNoise = Noise * 2-1;
    float2 CameraSize = float2(unity_OrthoParams.x, unity_OrthoParams.y);

    float2 Out = (RemappedNoise * strength) / CameraSize;
    return Out;
}
#ifdef CAUSTICS
float3 RGBSplit(float Split, Texture2D Texture, SamplerState Sampler, float2 UV)
{
    float2 UVR = UV + float2(Split, Split);
    float2 UVG = UV + float2(Split, -Split);
    float2 UVB = UV + float2(-Split, -Split);

    float r = SAMPLE_TEXTURE2D(Texture, Sampler, UVR).g;
    float g = SAMPLE_TEXTURE2D(Texture, Sampler, UVG).g;
    float b = SAMPLE_TEXTURE2D(Texture, Sampler, UVB).g;

    return float3(r,g,b);
}
float3 Toon_GetCaustics(float2 uv, SamplerState Sampler, float4 visuals, Texture2D Texture)
{
    float split = visuals.y * 0.01;
    float2 speed = _Time.x*visuals.z;
    float scale = visuals.w;
    float2 uv1 = speed + uv*1/scale;
    float2 uv2 = speed * float2(-1.07,-1.437) * 1.777 + uv*1/scale;
    uv2 *= 0.777;
    float3 texture_1 = RGBSplit(split, Texture, Sampler, uv1);
    float3 texture_2 = RGBSplit(split, Texture, Sampler, uv2);
    float3 texture_combined = min(texture_1, texture_2);
    return visuals.x * 10 * texture_combined;
}
#endif
float3 NormalStrength(float3 In, float Strength)
{
    return float3(In.rg * Strength, lerp(1, In.b, saturate(Strength)));
}
float3 UnpackNormals(float4 packedNormal, float scale = 1.0)
{
    packedNormal.r *= 0.5;
    float3 normal;
    normal.xy = packedNormal.rg * 2.0 - 1.0;
    normal.xy *= scale;
    normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
    return normal;
}
float3 Normals_float(float2 uv,float scale, float strength, float speed)
{
    float2 UV1 = Panner(uv, 1, speed, float2(0,0), 1/scale);
    float2 UV2 = Panner(uv, 1, -speed, float2(0,0), 1/scale * 0.5);
    float4 Texture1 = SAMPLE_TEXTURE2D(_NormalTex, sampler_NormalTex, UV1);
    float4 Texture2 = SAMPLE_TEXTURE2D(_NormalTex, sampler_NormalTex, UV2);
    Texture1.rgb = UnpackNormals(Texture1);
    Texture2.rgb = UnpackNormals(Texture2);
    float3 Strength1 = NormalStrength(Texture1.rgb, strength);
    float3 Strength2 = NormalStrength(Texture2.rgb, strength);

    return normalize(float3(Strength1.rg + Strength2.rg, Strength1.b * Strength2.b));
}
float3 Specular_float(Light light,float roughness, float3 normalDir, float3 viewDir)
{
    float3 L = normalize(light.direction);
    float3 N = normalize(normalDir);
    float3 V = normalize(viewDir);
    
    float3 H = SafeNormalize(L + V);
    float NdotH = saturate(dot(N, H)); 
    float LdotH = saturate(dot(L, H));
    roughness = roughness / 250;
    float Roughness2 = roughness * roughness;
    float d = NdotH * NdotH * (Roughness2 - 1.h) + 1.0001h;
    float specularTerm = Roughness2 / ((d * d) * max(0.1h, LdotH * LdotH) * (roughness + 0.5h) * 4);
    #if defined (SHADER_API_MOBILE)
        specularTerm = specularTerm - HALF_MIN;
        specularTerm = clamp(specularTerm, 0.0, 5.0); 
    #endif
    return specularTerm * light.color * light.distanceAttenuation;
}
float3 ScenePosition(float4 RefUV_World, Bindings_Water IN)
{
    float3 PerspectiveDivide = -IN.WorldSpaceViewDirection/IN.ScreenPosition.w.xxx;
    float SceneDepth = LinearEyeDepth(SHADERGRAPH_SAMPLE_SCENE_DEPTH(RefUV_World.xy), _ZBufferParams);;
    PerspectiveDivide = PerspectiveDivide*SceneDepth.xxx+_WorldSpaceCameraPos;

    SceneDepth = SHADERGRAPH_SAMPLE_SCENE_DEPTH(IN.ScreenPosition.xy / IN.ScreenPosition.w);
    SceneDepth = lerp(1-SceneDepth,SceneDepth,(_ProjectionParams.x +1)/ 2);
    SceneDepth = lerp(_ProjectionParams.y,_ProjectionParams.z,SceneDepth);
    float3 ViewSpacePos = float3(IN.ViewSpacePosition.xy, -SceneDepth);
    ViewSpacePos = mul(UNITY_MATRIX_I_V, float4(ViewSpacePos, 1)).xyz;
    return lerp(PerspectiveDivide,ViewSpacePos,unity_OrthoParams.w.xxx);
}
float DepthFade(float3 Scene_WorldPos, float Depth,float3 WorldSpacePosition)
{	
    Scene_WorldPos = WorldSpacePosition-Scene_WorldPos;
    float Depth_Exp = saturate(exp(-Scene_WorldPos.g/Depth));
    return Depth_Exp;
}
float2 RefractedUV(float3 Refract_World,float3 Refraction, float RefractionDepth, Bindings_Water IN)
{
    Bindings_Water _ScenePosition;
    _ScenePosition.WorldSpaceViewDirection = IN.WorldSpaceViewDirection;
    _ScenePosition.ViewSpacePosition = IN.ViewSpacePosition;
    _ScenePosition.ScreenPosition = IN.ScreenPosition;
    float2 WorldSpaceUV = float2(IN.WorldSpacePosition.x, IN.WorldSpacePosition.z);
    float DepthFade_Exponential = DepthFade(Refract_World, RefractionDepth, IN.WorldSpacePosition);
    float3 Refract = float3(Refraction.x, Refraction.y, Refraction.z*(1-DepthFade_Exponential));
    float2 RefractUV = RefractUV_float(WorldSpaceUV, Refract);
    RefractUV = IN.ScreenPosition.xy+RefractUV;
    
    float3 PerspectiveDivide = float3(RefractUV, 0.0)/IN.ScreenPosition.w.xxx;
    float3 Scene_World = ScenePosition((float4(PerspectiveDivide , 1.0)), _ScenePosition);
    float2 Branch_Out = step(0,(IN.AbsoluteWorldSpacePosition-Scene_World).y) ? RefractUV : IN.ScreenPosition.xy;
    float3 PerspectiveDivide_Out = float3(Branch_Out, 0.0)/IN.ScreenPosition.w.xxx;
    return PerspectiveDivide_Out.xy;
}
SurfaceDescription SurfaceDescriptionFunction(SurfaceDescriptionInputs IN)
{
    SurfaceDescription surface = (SurfaceDescription)0;
    Bindings_Water Water_Out;
    Water_Out.WorldSpaceNormal = IN.WorldSpaceNormal;
    Water_Out.WorldSpaceViewDirection = _WorldSpaceCameraPos.xyz - IN.WorldSpacePosition;
    Water_Out.WorldSpacePosition = IN.WorldSpacePosition;
    Water_Out.ViewSpacePosition = IN.ViewSpacePosition;
    Water_Out.AbsoluteWorldSpacePosition = IN.AbsoluteWorldSpacePosition;
    Water_Out.ScreenPosition = IN.ScreenPosition;

    float4 ScreenPos = float4(IN.ScreenPosition.xy / IN.ScreenPosition.w, 0, 0);
    float3 Scene_World = ScenePosition(ScreenPos, Water_Out);
    half vPos = lerp(saturate(-IN.vPos * _NearAlpha),1,step(0.2,_NearAlpha));
    float2 RefractedUV_World = RefractedUV(Scene_World,_Refraction, _Refraction.w, Water_Out);
    half DepthFade_Exponential = DepthFade(Scene_World, _ColorDepth, IN.WorldSpacePosition);
//渐变颜色
    half4 GradientColor = lerp(_DeepColor,_ShallowColor,DepthFade_Exponential);
//反射
    half3 flectionTex = SAMPLE_TEXTURE2D(_ReflectionTex, sampler_ReflectionTex, RefractedUV_World).rgb;
    half FresnelEffect = pow((1.0 - saturate(dot(normalize(IN.WorldSpaceNormal), normalize(Water_Out.WorldSpaceViewDirection)))), 1);
    GradientColor.rgb = lerp(GradientColor.rgb,flectionTex*(0.2 + FresnelEffect*0.7).xxx*_SkyColor,_ReflectionStrength);
    surface.Color = GradientColor.rgb;
//计算海浪
    half FoamDepth_Exponential = DepthFade(Scene_World, _WaveParams.x*IN.VertexColor.r, IN.WorldSpacePosition);
    half wave1 = SAMPLE_TEXTURE2D(_FoamTex, sampler_FoamTex, half2(FoamDepth_Exponential - _Time.x*_WaveParams.z, 0)*_WaveParams.y).r;
    surface.Color += wave1*FoamDepth_Exponential*_WaveParams.w*vPos*IN.VertexColor.r;
//焦散
#ifdef CAUSTICS
    half CausticsDepth_Exponential = DepthFade(Scene_World, _CausticsDepth, IN.WorldSpacePosition);
    half3 Caustics = Toon_GetCaustics(Scene_World.xz, _CustomFunction_Sampler_Linear_Repeat, _CausticsVisuals, _FoamTex);
    Caustics *= CausticsDepth_Exponential.xxx*IN.VertexColor.g*(1-FoamDepth_Exponential)*vPos;
    surface.Color += Caustics;
#endif
    surface.alpha = GradientColor.w*vPos*IN.VertexColor.a;
    return surface;
}
#endif