Shader "Unlit/WaterShader"
{
    Properties
    {
        //_MainTex("Albedo (RGB)", 2D) = "white" {}
        //_FlowMap("FlowMap", 2D) = "white" {}
        //_FlowSpeed("FlowSpeed",Range(0,1)) = 1
        //_UJump("U jump per phase", Range(-0.25, 0.25)) = 0.25
        //_VJump("V jump per phase", Range(-0.25, 0.25)) = -0.25
        //_FlowStrength("Flow Strength", Float) = 1
        //_FlowOffset("Flow Offset", Float) = 0
        //_NormalTex("Normal", 2D) = "bump" {}
        _SurfaceMap("SurfaceMap",2D) = "white" {}
        //<反射
        _ReflectionTex("ReflectionRT", 2D) = "white" {}
        _ReflectionIntensity("ReflectionsIntensity", Range(0, 3)) = 1
        _ReflectionColorIntensity("ReflectionsColorIntensity",Range(0,1)) = 1
        //反射>
        //<折射
        _RefractionIntensity("RefractionIntensity", Range(0,1)) = 1
        _RefractionColorIntensity("RefractionColorIntensity",Range(0,1)) = 1
        //折射>
        //<焦散
        _CausticsTex("CausticsTex", 2D) = "white" {}
        _Caustics1_ST("Caustics 1 ST", Vector) = (1,1,0,0)
        _Caustics2_ST("Caustics 2 ST", Vector) = (1,1,0,0)
        _Caustics1_Speed("Caustics 1 Speed", Vector) = (1, 1, 0 ,0)
        _Caustics2_Speed("Caustics 2 Speed", Vector) = (1, 1, 0 ,0)
        _SplitRGB("SplitRGB",Range(0,1)) = 0
        _CausticsColorIntensity("CausticsColorIntensity",Float) = 4
        _CausticsTop("CausticsTop",Float) = 0.2
        _CausticsBottom("CausticsBottom",Float) = 2
        //焦散>
        //<泡沫
        //_FoamMap("FoamMap", 2D) = "white" {}
        //泡沫>
    }
    SubShader
    {
        Tags { 
            "Queue" = "Transparent" "RenderType" = "Transparent" "PreviewType" = "Plane" "RenderPipeline" = "UniversalPipeline"
        }
        
        Pass
        {
            Name "WaterShading"
            Tags{"LightMode" = "UniversalForward"}
            Blend One OneMinusSrcAlpha
            ZWrite Off
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "WaterInput.hlsl"
            #include "WaterLighting.hlsl"
            #include "CommonUtilities.hlsl"
            #define UNITY_PROJ_COORD(a) a.xyzw/a.w
            #define UNITY_SAMPLE_DEPTH(a) a.r
            float4      _LightColor0;
            sampler2D   _CameraDepthTexture;
            float4      _CameraDepthTexture_TexelSize;

            //<反射
            sampler2D   _ReflectionTex;
            float       _ReflectionIntensity;
            float       _ReflectionColorIntensity;
            //反射>
            //<折射
            sampler2D   _CameraOpaqueTexture;
            float       _RefractionIntensity;
            float       _RefractionColorIntensity;
            //折射>
            //<着色
            //sampler2D   _NormalTex, _MainTex;
            //float4      _NormalTex_ST, _MainTex_ST;
            //着色>
            //<FlowMap
            //sampler2D   _FlowMap;
            //float       _FlowSpeed;
            //float       _UJump;
            //float       _VJump;
            //float       _FlowStrength;
            //float       _FlowOffset;
            //FlowMap>
            //<焦散
            sampler2D   _CausticsTex;
            float4		_CausticsTex_ST;
            float4		_Caustics1_ST;
            float4		_Caustics2_ST;
            float4		_Caustics1_Speed;
            float4		_Caustics2_Speed;
            float		_SplitRGB;
            float       _CausticsColorIntensity;
            float       _CausticsTop;
            float       _CausticsBottom;
            //焦散>
            struct VertexInput {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 tangent : TANGENT;
                float2 texcoord0 : TEXCOORD0;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float2 uv0 : TEXCOORD0;
                float3 posWorld : TEXCOORD1;
                float3 normalDir : TEXCOORD2;
                float4 projPos : TEXCOORD3;
                float4 tangent : TEXCOORD4;
                float4 uv : TEXCOORD5;
                float3 ray : TEXCOORD6;
            };

            //<辅助函数
            float Deg2Rad(float deg) 
            {
                return deg * (PI / 180.0f);
            }
            float3 CreateBinormal(float3 normal, float3 tangent, float binormalSign) {
                return cross(normal, tangent.xyz) *
                    (binormalSign * unity_WorldTransformParams.w);
            }
            void InitializeFragmentNormal(inout VertexOutput i, float3 tangentSpaceNormal) {
                float3 binormal = CreateBinormal(i.normalDir, i.tangent.xyz, i.tangent.w);
                i.normalDir = normalize(
                    tangentSpaceNormal.x * i.tangent +
                    tangentSpaceNormal.y * binormal +
                    tangentSpaceNormal.z * i.normalDir
                );
            }
            //float3 FlowUVW(float2 uv, float2 flowVector, float2 jump,
            //    float flowOffset, float time, bool flowB) 
            //{
            //    float phaseOffset = flowB ? 0.5 : 0;
            //    float progress = frac(time + phaseOffset);
            //    float3 uvw;
            //    uvw.xy = uv - flowVector * (progress + flowOffset);
            //    uvw.xy *= _MainTex_ST.xy;
            //    uvw.xy += phaseOffset;
            //    uvw.xy += (time - progress) * jump;
            //    uvw.z = 1 - abs(1 - 2 * progress);
            //    return uvw;
            //}
            //辅助函数>
            
            //<光照计算
            half3 Scattering(half depth)
            {
                return SAMPLE_TEXTURE2D(_AbsorptionScatteringRamp, sampler_AbsorptionScatteringRamp, half2(depth, 0.75f)).rgb;//TODO 按照BoatAttack的写法，此处采样的值和Absorption一样？
            }

            half3 Absorption(half depth)
            {
                return SAMPLE_TEXTURE2D(_AbsorptionScatteringRamp, sampler_AbsorptionScatteringRamp, half2(depth, 0.0f)).rgb;
            }
            //光照计算>
            //<获取深度差
            float getDepthDifference(float2 uv,float trasparentPartDepth)
            {
                float opaqueSceneDepth = LinearEyeDepth(UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, uv)), _ZBufferParams);
                return opaqueSceneDepth - trasparentPartDepth;
            }
            //获取深度差>
            //<焦散
            float3 GetCausticColor(float2 uv)
            {
                float s = _SplitRGB;
                float r = tex2D(_CausticsTex, uv + float2(+s, +s)).r;
                float g = tex2D(_CausticsTex, uv + float2(+s, -s)).g;
                float b = tex2D(_CausticsTex, uv + float2(-s, -s)).b;
                return float3(r, g, b);
            }
            float4 GetCaustic(VertexOutput i)
            {
                float2 screenuv = UNITY_PROJ_COORD(i.projPos);
                float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, screenuv));
                float viewDepth = Linear01Depth(depth, _ZBufferParams) * _ProjectionParams.z;
                float3 viewPos = i.ray * viewDepth / i.ray.z;
                //转化到世界空间坐标
                float4 worldPos = mul(unity_CameraToWorld, float4(viewPos, 1.0));
                //转化为物体空间坐标
                float3 objectPos = TransformWorldToObject(worldPos);
                //使用物体空间坐标的xz坐标作为采样uv
                float2 uv = objectPos.xz * _CausticsTex_ST.xy + 0.5;//_CausticsTex_ST.xy的设置需要和模型的uv设置相匹配
                float2 uv1 = uv * _Caustics1_ST.xy + _Caustics1_ST.zw;
                uv1 += _Caustics1_Speed.xy * _Time.y;
                float2 uv2 = uv * _Caustics2_ST.xy + _Caustics2_ST.zw;
                uv2 += _Caustics2_Speed.xy * _Time.y;
                float3 col = min(GetCausticColor(uv1), GetCausticColor(uv2));
                //return float4(-objectPos.y.xxx,1);
                return float4(col * _CausticsColorIntensity, col.r) * saturate(_CausticsBottom + objectPos.y) * saturate(-objectPos.y - _CausticsTop);
            }
            //焦散>
            VertexOutput vert(VertexInput v)
            {
                VertexOutput o = (VertexOutput)0;
                o.uv0 = v.texcoord0;
                o.normalDir = TransformObjectToWorldNormal(v.normal);
                o.pos = TransformObjectToHClip(v.vertex);
                o.posWorld = TransformObjectToWorld(v.vertex);
                o.projPos = ComputeScreenPos(o.pos);
                o.projPos.z = -mul(UNITY_MATRIX_MV, v.vertex).z;
                //COMPUTE_EYEDEPTH(o.projPos.z);
                o.tangent = float4(TransformObjectToWorldDir(v.tangent.xyz), v.tangent.w);
                //<新的法线算法
                float FactorNoise = ((noise((o.posWorld.xz * 0.5) + _Time.y) + noise((o.posWorld.xz * 1) + _Time.y)) * 0.25 - 0.5) + 1;
                o.uv.zw = o.posWorld.xz * 0.1h + _Time.y * 0.05h;// +(FactorNoise * 0.1);
                o.uv.xy = o.posWorld.xz * 0.4h - _Time.y * 0.1h;// +(FactorNoise * 0.2);
                o.ray = TransformWorldToView(TransformObjectToWorld(v.vertex)) * float3(-1, -1, 1);
                //新的法线算法>
                return o;
            }

            float4 frag (VertexOutput i) : SV_Target
            {
                //#if UNITY_UV_STARTS_AT_TOP
                //    float grabSign = -_ProjectionParams.x;
                //#else
                //    float grabSign = _ProjectionParams.x;
                //#endif
                //<Flowmap
                //float2 flowVector = tex2D(_FlowMap, i.uv0).rg * 2 - 1;
                //flowVector *= _FlowStrength;
                //float noise = tex2D(_FlowMap, i.uv0).a;
                //float time = _Time.y * _FlowSpeed + noise;
                //float2 jump = float2(_UJump, _VJump);
                //float3 uvwA = FlowUVW(i.uv0, flowVector, jump,_FlowOffset, time, false);
                //float3 uvwB = FlowUVW(i.uv0, flowVector, jump, _FlowOffset, time, true);
                //float4 texA = tex2D(_MainTex, uvwA.xy) * uvwA.z;
                //float4 texB = tex2D(_MainTex, uvwB.xy) * uvwB.z;
                //float3 normalA = UnpackNormal(tex2D(_NormalTex, uvwA.xy)) * uvwA.z;
                //float3 normalB = UnpackNormal(tex2D(_NormalTex, uvwB.xy)) * uvwB.z;
                //float3 tangentNormal = normalize(normalA + normalB);
                //Flowmap>
                float trasparentPartDepth = i.projPos.z;
                //<新的法线算法
                float depthDifference1 = getDepthDifference(UNITY_PROJ_COORD(i.projPos), trasparentPartDepth);
                half2 detailBump1 = SAMPLE_TEXTURE2D(_SurfaceMap, sampler_SurfaceMap, i.uv.zw * _SurfaceMap_ST.xy).xy * 2 - 1;
                half2 detailBump2 = SAMPLE_TEXTURE2D(_SurfaceMap, sampler_SurfaceMap, i.uv.xy * _SurfaceMap_ST.xy).xy * 2 - 1;
                half2 detailBump = (detailBump1 + detailBump2 * 0.5) * saturate(depthDifference1 * 0.25 + 0.25);
                i.normalDir += half3(detailBump.x, 0, detailBump.y)/* * _BumpScale*/;
                i.normalDir = normalize(i.normalDir);
                //新的法线算法>
                
                float3 V = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
                float3 N = i.normalDir;
                float3 viewReflectDirection = reflect(-V, N);
                Light mainLight = GetMainLight();
                float3 L = normalize(mainLight.direction);
                float3 H = normalize(V + L);
                float3 lightColor = _LightColor0.rgb;
                
                //<折射
                float2 uvOffset = i.normalDir.xz *_RefractionIntensity;
                uvOffset.y *= _CameraDepthTexture_TexelSize.z * abs(_CameraDepthTexture_TexelSize.y);//根据窗口纵横比矫正Offset

                float depthDifferenceNoOffset = getDepthDifference(UNITY_PROJ_COORD(i.projPos),trasparentPartDepth);

                uvOffset *= saturate(depthDifferenceNoOffset);//根据深度差缩放uv的偏移程度
                float2 RefractionUVs = UNITY_PROJ_COORD(i.projPos) + uvOffset;//TODO uvOffset在y轴方向的偏移会导致采样到天空的纹理,按照折射的原理y轴方向应该向上偏移

                float depthDifference = getDepthDifference(RefractionUVs, trasparentPartDepth);
                if (depthDifference < 0)//TODO 只Offset水下的部分
                {
                    RefractionUVs = UNITY_PROJ_COORD(i.projPos);
                }

                float3 backgroundColor = tex2D(_CameraOpaqueTexture, RefractionUVs).rgb;
                float fogFactor = 1- exp2(-0.25 * depthDifference);
                float3 RefractionColor = backgroundColor * Absorption(depthDifference * (1.0f / 6.0f));//TODO MagicNumber
                //折射>
                //<反射
                float2 ReflectionUVs = RefractionUVs + float2(0.01, 0.01);
                half fresnelTerm = CalculateFresnelTerm(i.normalDir, V);
                float4 ReflectionColor = tex2D(_ReflectionTex, ReflectionUVs) * fresnelTerm;//乘以菲涅尔项保证倒影只出现在视角与法线夹角较大的位置
                //反射>
                //<着色 
                BRDFData brdfData;
                InitializeBRDFData(half3(0, 0, 0), 0, half3(1, 1, 1), 0.9, 1, brdfData);
                half3 spec = DirectBDRF(brdfData, N, mainLight.direction, V) * mainLight.color;
                half3 GI = SampleSH(N);
                half3 sss = (mainLight.color + GI);
                sss *= Scattering(depthDifference * (1.0f/6.0f));
                //着色> 

                //<泡沫
                //half3 foamMap = SAMPLE_TEXTURE2D(_FoamMap, sampler_FoamMap, i.uv.zw).rgb;
                ////half foamMask = saturate(length(foamMap));
                //half foamMask = foamMap.r;// saturate(length(foamMap));
                ////return float4(foamMask.rrr * saturate(1- depthDifferenceNoOffset), 1);
                //float3 foam = foamMask.rrr * saturate(1 - depthDifferenceNoOffset);
                //foam = max(foam, (ReflectionColor.rgb + spec) + (sss + RefractionColor));
                //泡沫>
                //<焦散
                //return GetCaustic(i);
                //焦散>
                //return float4(lerp((ReflectionColor.rgb + spec) + (sss + RefractionColor), foam, saturate(1 - depthDifferenceNoOffset)), 1) + GetCaustic(i) * saturate(2.0 - depthDifferenceNoOffset);
                return float4((ReflectionColor.rgb + spec) + (sss + RefractionColor), 1) + GetCaustic(i);// *saturate(2.0 - depthDifferenceNoOffset)* saturate(depthDifferenceNoOffset - 0.5);//无浪花，岸线无明显分割
                //return float4(lerp((ReflectionColor.rgb + spec) + (sss + RefractionColor), foam, saturate(1 - depthDifferenceNoOffset)), 1) + GetCaustic(i) * saturate(2.0 - depthDifferenceNoOffset) * saturate(depthDifferenceNoOffset - 0.5);
            }
            ENDHLSL
        }
    }
}
