{"id":849,"date":"2021-03-19T19:27:52","date_gmt":"2021-03-19T11:27:52","guid":{"rendered":"http:\/\/meecarlo.com\/?p=849"},"modified":"2021-03-19T19:29:12","modified_gmt":"2021-03-19T11:29:12","slug":"gerstner-wave","status":"publish","type":"post","link":"https:\/\/meecarlo.com\/old\/2021\/03\/19\/gerstner-wave\/","title":{"rendered":"Gerstner wave"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>Shader \"Unlit\/GerstnerWaveStandard\"\r\n{\r\n    Properties\r\n    {\r\n        _MainTex (\"Texture\", 2D) = \"white\" {}\r\n        &#91;Header(BaseShading)]\r\n        _BaseMap (\"Example Texture\", 2D) = \"white\" { }\r\n        &#91;HDR]_BaseColor (\"Base Colour\", Color) = (0, 0.66, 0.73, 1)\r\n        _WaterFogColor (\"Water Fog Colour\", Color) = (0, 0.66, 0.73, 1)\r\n        _FogDensity (\"Fog Density\", range(0, 1)) = 0.1\r\n        _NormalMap (\"Normal Map\", 2D) = \"white\" { }\r\n        _NormalScale (\"Normal Scale\", Range(0, 1)) = 0.1\r\n        _Shininess (\"High Light Roughness\", Range(0, 0.1)) = 0.01\r\n        &#91;Space(20)]\r\n        &#91;Header(Reflection)]\r\n        _Skybox (\"Skybox\", Cube) = \"white\" { }\r\n        &#91;Header(Refractive)]\r\n        _AirRefractiveIndex (\"Air Refractive Index\", Float) = 1.0\r\n        _WaterRefractiveIndex (\"Water Refractive Index\", Float) = 1.333\r\n        _FresnelPower (\"Fresnel Power\", Range(0.1, 50)) = 5\r\n        _RefractionStrength (\"Refraction Strength\", Range(0, 1)) = 0.1\r\n        \r\n        &#91;Space(20)]\r\n        &#91;Header(SSS)]\r\n        _FrontSubsurfaceDistortion (\"Front Subsurface Distortion\", Range(0, 1)) = 0.5\r\n        _BackSubsurfaceDistortion (\"Back Subsurface Distortion\", Range(0, 1)) = 0.5\r\n        _FrontSSSIntensity (\"Front SSS Intensity\", float) = 0.2\r\n        _HeightCorrection (\"SSS Height Correction\", float) = 6\r\n        \r\n        &#91;Space(20)]\r\n        &#91;Header(Foam)]\r\n        _FoamIntensity (\"Foam Intensity\", float) = 0.5\r\n        _FoamNoiseTex (\"Foam Noise\", 2D) = \"white\" { }\r\n        \r\n        &#91;Space(20)]\r\n        &#91;Header(Caustic)]\r\n        _CausticIntensity (\"Caustic Intensity\", float) = 0.5\r\n        _CausticTex (\"Caustic Texture\", 2D) = \"white\" { }\r\n        _Caustics_Speed (\"Caustics Speed,(x,y)&amp;(z,w)\", Vector) = (1, 1, -1, -1)\r\n        \r\n        &#91;Space(20)]\r\n        &#91;Header(Waves)]\r\n        _Speed (\"Speed\", float) = 0.2\r\n        _Frequency (\"Frequency\", float) = 2\r\n        _WaveA (\"Wave A (dir, steepness, wavelength)\", Vector) = (1, 0, 0.5, 10)\r\n        _WaveB (\"Wave B\", Vector) = (0, 1, 0.25, 20)\r\n        _WaveC (\"Wave C\", Vector) = (1, 1, 0.15, 10)\r\n        _WaveD (\"Wave D\", Vector) = (0, 1, 0.25, 20)\r\n        _WaveE (\"Wave E\", Vector) = (1, 1, 0.15, 10)\r\n        _WaveF (\"Wave F\", Vector) = (0, 1, 0.25, 20)\r\n        _WaveG (\"Wave G\", Vector) = (1, 1, 0.15, 10)\r\n        _WaveH (\"Wave H\", Vector) = (0, 1, 0.25, 20)\r\n        _WaveI (\"Wave I\", Vector) = (1, 1, 0.15, 10)\r\n        _WaveJ (\"Wave J\", Vector) = (1, 1, 0.15, 10)\r\n        _WaveK (\"Wave K\", Vector) = (1, 1, 0.15, 10)\r\n        _WaveL (\"Wave L\", Vector) = (1, 1, 0.15, 10)\r\n        &#91;Space(20)]\r\n        &#91;Header(Tessellation)]\r\n        _TessellationUniform (\"Tessellation Uniform\", Range(1, 64)) = 1\r\n        _TessellationEdgeLength (\"Tessellation Edge Length\", Range(5, 100)) = 50\r\n        &#91;Toggle(_TESSELLATION_EDGE)]_TESSELLATION_EDGE (\"TESSELLATION EDGE\", float) = 0\r\n\r\n\r\n\r\n        &#91;Space(20)]\r\n        &#91;Header(Others)]\r\n        _shadowAttenuation(\"shadowAttenuation\",float)=0.2\r\n        _CameraOpaqueTexture(\"_CameraOpaqueTexture\",2D)=\"white\"{}\r\n    }\r\n    SubShader\r\n    {\r\n        Tags { \"RenderType\" = \"Transparent\"  \"RenderQueue\" = \"Transparent\" }\r\n        \r\n        ZWrite Off\r\n        ZTest On\r\n        CGPROGRAM\r\n        #include \"Lighting.cginc\"\r\n        #include \"unityCg.cginc\"\r\n        float4 _BaseMap_ST, _FoamNoiseTex_ST, _CausticTex_ST;\r\n        float4 _BaseColor, _WaterFogColor, _Caustics_Speed;\r\n        float4 _NormalMap_ST;\r\n        float4 _WaveA, _WaveB, _WaveC, _WaveD, _WaveE, _WaveF, _WaveG, _WaveH, _WaveI, _WaveJ, _WaveK, _WaveL;\r\n        float _Speed, _Frequency, _NormalScale, _AirRefractiveIndex, _WaterRefractiveIndex, _FresnelPower;\r\n        float _RefractionStrength, _FogDensity, _Shininess, _FrontSubsurfaceDistortion, _BackSubsurfaceDistortion;\r\n        float _FrontSSSIntensity, _HeightCorrection, _FoamIntensity, _CausticIntensity;\r\n        ENDCG\r\n\r\n        Pass\r\n        {\r\n            Name \"Example\"\r\n            Tags { \"LightMode\" = \"ForwardBase\" }\r\n            \r\n            ZWrite off\r\n            CGPROGRAM\r\n            #pragma vertex vert\r\n            #pragma fragment frag\r\n            \/\/ make fog work\r\n           \/\/ #pragma multi_compile_fog\r\n\r\n            #include \"UnityCG.cginc\"\r\n            #include \"AutoLight.cginc\"\r\n            #include \"Lighting.cginc\"\r\n\r\n            struct a2v\r\n            {\r\n                float4 positionOS: POSITION;\r\n                float2 uv: TEXCOORD0;\r\n                float3 normal: NORMAL;\r\n                float4 color: COLOR;\r\n            };\r\n\r\n            struct v2f\r\n            {\r\n                float4 positionCS: SV_POSITION;\r\n                float2 uv: TEXCOORD0;\r\n                float3 normalWS: TEXCOORD1;\r\n                float3 positionWS: TEXCOORD2;\r\n                float3 tangentWS: TEXCOORD3;\r\n                float4 scrPos: TEXCOORD4;\r\n                float heightOS: TEXCOORD5;\r\n                float fogFactor: TEXCOORD6;\r\n                float4 color: COLOR;\r\n            };\r\n\r\n            samplerCUBE _Skybox;\r\n            float4 _Skybox_ST;\r\n            sampler2D _CameraOpaqueTexture;\r\n            float4 _CameraOpaqueTexture_ST;\r\n            sampler2D _FoamNoiseTex;\r\n            float2 _FoamNoiseTex_ST;\r\n            sampler2D _CausticTex;\r\n            float4 _CausticTex_ST;\r\n            float _Speed, _Frequency, _NormalScale, _AirRefractiveIndex, _WaterRefractiveIndex, _FresnelPower;\r\n            float4 _WaveA, _WaveB, _WaveC, _WaveD, _WaveE, _WaveF, _WaveG, _WaveH, _WaveI, _WaveJ, _WaveK, _WaveL;\r\n            float4 _NormalMap_ST;\r\n            float _RefractionStrength, _FogDensity, _Shininess, _FrontSubsurfaceDistortion, _BackSubsurfaceDistortion;\r\n            float4 _BaseColor, _WaterFogColor, _Caustics_Speed;\r\n            float _shadowAttenuation;\r\n            float _FrontSSSIntensity, _HeightCorrection, _FoamIntensity, _CausticIntensity;\r\n\r\n\r\n            sampler2D _MainTex;\r\n            float4 _MainTex_ST;\r\n            sampler2D _NormalMap;\r\n\r\n            \/\/-------------GenrateGerstnerWave-------------\r\n            float3 GerstnerWave(\r\n                float4 wave, float3 p, inout float3 tangent, inout float3 binormal\r\n            )\r\n            {\r\n                float steepness = wave.z;\r\n                float wavelength = wave.w;\r\n                float k = 2 * UNITY_PI \/ wavelength;\r\n                float c = sqrt(9.8 \/ k);\r\n                float2 d = normalize(wave.xy) * _Frequency;\r\n                float f = k * (dot(d, p.xz) - c * _Time.y * _Speed);\r\n                float a = steepness \/ k;\r\n        \r\n                tangent += float3(\r\n                    - d.x * d.x * (steepness * sin(f)),\r\n                    d.x * (steepness * cos(f)),\r\n                    - d.x * d.y * (steepness * sin(f))\r\n                );\r\n                binormal += float3(\r\n                    - d.x * d.y * (steepness * sin(f)),\r\n                    d.y * (steepness * cos(f)),\r\n                    - d.y * d.y * (steepness * sin(f))\r\n                );\r\n                return float3(\r\n                    d.x * (a * cos(f)),\r\n                    a * sin(f),\r\n                    d.y * (a * cos(f))\r\n                );\r\n            }\r\n              \r\n            \/\/-----------CalculateFresnel------------------\r\n            float CalculateFresnel(float3 viewDir, float3 normal)\r\n            {\r\n                float R_0 = (_AirRefractiveIndex - _WaterRefractiveIndex) \/ (_AirRefractiveIndex + _WaterRefractiveIndex);\r\n                R_0 *= R_0;\r\n                return R_0 + (1.0 - R_0) * pow((1.0 - saturate(dot(viewDir, normal))), _FresnelPower);\r\n            }\r\n            \r\n            \r\n            \r\n            \r\n            half3 Highlights(half3 positionWS, half roughness, half3 normalWS, half3 viewDirectionWS)\r\n            {\r\n                \/\/Light mainLight = GetMainLight();\r\n                half roughness2 = roughness * roughness;\r\n                half3 halfDir = normalize(_WorldSpaceLightPos0.xyz + viewDirectionWS);\r\n                half NoH = saturate(dot(normalize(normalWS), halfDir));\r\n                half LoH = saturate(dot(_WorldSpaceLightPos0.xyz, halfDir));\r\n                \/\/ GGX Distribution multiplied by combined approximation of Visibility and Fresnel\r\n                half d = NoH * NoH * (roughness2 - 1) + 1.0001;\r\n                half LoH2 = LoH * LoH;\r\n                half specularTerm = roughness2 \/ ((d * d) * max(0.1, LoH2) * (roughness + 0.5) * 4);\r\n                specularTerm = min(specularTerm, 10);\r\n        \r\n                return specularTerm * _LightColor0.rgb * _shadowAttenuation;\r\n            }\r\n            \r\n\r\n\r\n            \/\/-------------GetOddNegativeScale----------------\r\n            float GetOddNegativeScale()\r\n            {\r\n                return unity_WorldTransformParams.w;\r\n            }\r\n\r\n            \/\/------------CreateTangentToWorld---------------\r\n            float3x3 CreateTangentToWorld(float3 normal, float3 tangent, float flipSign)\r\n            {\r\n            \/\/ For odd-negative scale transforms we need to flip the sign\r\n            float sgn = flipSign * GetOddNegativeScale();\r\n            float3 bitangent = cross(normal, tangent) * sgn;\r\n\r\n            return float3x3(tangent, bitangent, normal);\r\n            }\r\n            \r\n            \/\/-----------TransformTangentToWorld----------\r\n            float3 TransformTangentToWorld(float3 dirTS, float3x3 tangentToWorld)\r\n            {\r\n                \/\/ Note matrix is in row major convention with left multiplication as it is build on the fly\r\n                return mul(dirTS, tangentToWorld);\r\n            }\r\n            float3 GetCameraPositionWS()\r\n            {\r\n                return _WorldSpaceCameraPos;\r\n            }\r\n\r\n            \/\/-----------SampleSceneDepth--------------\r\n            sampler2D _CameraDepthTexture;\r\n            sampler2D sampler_CameraDepthTexture;\r\n            float SampleSceneDepth(float2 uv)\r\n            {\r\n                return tex2D(_CameraDepthTexture, UnityStereoTransformScreenSpaceTex(uv)).r;\r\n            }\r\n\r\n\r\n\r\n            float SubsurfaceScattering(float3 viewDir, float3 lightDir, float3 normalDir,\r\n            float frontSubsurfaceDistortion, float backSubsurfaceDistortion, float frontSSSIntensity, float thickness)\r\n            {\r\n            \/\/\u5206\u522b\u8ba1\u7b97\u6b63\u9762\u548c\u53cd\u9762\u7684\u6b21\u8868\u9762\u6563\u5c04\r\n            float3 frontLitDir = normalDir * frontSubsurfaceDistortion - lightDir;\r\n            float3 backLitDir = normalDir * backSubsurfaceDistortion + lightDir;\r\n            float frontsss = saturate(dot(viewDir, -frontLitDir));\r\n            float backsss = saturate(dot(viewDir, -backLitDir));\r\n        \r\n            float result = saturate(frontsss * frontSSSIntensity + backsss) * thickness;\r\n            return result;\r\n            }\r\n            \/*\r\n            \/\/------------Light------------------\r\n            struct Light\r\n            {\r\n                half3   direction;\r\n                half3   color;\r\n                half    distanceAttenuation;\r\n                half    shadowAttenuation;\r\n            };\r\n\r\n            \/\/-----------GetMainLight-------------\r\n            Light GetMainLight()\r\n            {\r\n                Light light;\r\n                light.direction = _WorldSpaceLightPos0.xyz;\r\n                \/\/ unity_LightData.z is 1 when not culled by the culling mask, otherwise 0.\r\n                light.distanceAttenuation = unity_LightData.z;\r\n            #if defined(LIGHTMAP_ON) || defined(_MIXED_LIGHTING_SUBTRACTIVE)\r\n                \/\/ unity_ProbesOcclusion.x is the mixed light probe occlusion data\r\n                light.distanceAttenuation *= unity_ProbesOcclusion.x;\r\n            #endif\r\n                light.shadowAttenuation = 1.0;\r\n                light.color = _MainLightColor.rgb;\r\n\r\n                return light;\r\n            }\r\n            *\/\r\n\r\n            v2f vert (a2v v)\r\n            {\r\n                v2f o;\r\n                float3 tangent = float3(1, 0, 0);\r\n                float3 binormal = float3(0, 0, 1);\r\n                float3 p = v.positionOS;\r\n\r\n                p += GerstnerWave(_WaveA, v.positionOS.xyz, tangent, binormal);\r\n                p += GerstnerWave(_WaveB, v.positionOS.xyz, tangent, binormal);\r\n                p += GerstnerWave(_WaveC, v.positionOS.xyz, tangent, binormal);\r\n                p += GerstnerWave(_WaveD, v.positionOS.xyz, tangent, binormal);\r\n                p += GerstnerWave(_WaveE, v.positionOS.xyz, tangent, binormal);\r\n                p += GerstnerWave(_WaveF, v.positionOS.xyz, tangent, binormal);\r\n                p += GerstnerWave(_WaveG, v.positionOS.xyz, tangent, binormal);\r\n                p += GerstnerWave(_WaveH, v.positionOS.xyz, tangent, binormal);\r\n                p += GerstnerWave(_WaveI, v.positionOS.xyz, tangent, binormal);\r\n                p += GerstnerWave(_WaveJ, v.positionOS.xyz, tangent, binormal);\r\n                p += GerstnerWave(_WaveK, v.positionOS.xyz, tangent, binormal);\r\n                p += GerstnerWave(_WaveL, v.positionOS.xyz, tangent, binormal);\r\n\r\n\r\n                o.heightOS = p.y;\r\n                float3 normal = normalize(cross(binormal, tangent));\r\n                UNITY_INITIALIZE_OUTPUT(v2f, o);\r\n                o.positionCS = UnityObjectToClipPos(p);\r\n                o.normalWS = UnityObjectToWorldNormal(v.normal);\r\n                o.positionWS = mul(unity_ObjectToWorld,v.positionOS);\r\n                o.scrPos = ComputeScreenPos(o.positionCS);\r\n                o.uv = TRANSFORM_TEX(v.uv, _MainTex);\r\n                \/\/UNITY_TRANSFER_FOG(o,o.positionCS);\r\n                return o;\r\n            }\r\n\r\n            fixed4 frag (v2f i) : SV_Target\r\n            {\r\n                float3 normalWS = normalize(i.normalWS);\r\n                \/\/-------------normal----------\r\n                float3x3 TtoW = CreateTangentToWorld(i.normalWS, i.tangentWS, 1);\r\n                fixed4 normalTS = tex2D(_NormalMap,i.uv);\r\n                normalTS.xyz = normalize(UnpackNormal(normalTS));\r\n                normalWS = lerp(normalWS,normalize(TransformTangentToWorld(normalTS,TtoW)),_NormalScale);\r\n                normalWS = normalize(normalWS);\r\n\r\n                \/\/------------reflection-----------\r\n                float3 viewDirectionWS = normalize(GetCameraPositionWS() - i.positionWS.xyz);\r\n                float3 reflectDir = reflect(-viewDirectionWS, normalWS);\r\n                float4 reflectCol = texCUBE(_Skybox,reflectDir);\r\n                \/\/------------refraction------------\r\n                float2 scrPos = i.scrPos \/ i.scrPos.w;\r\n                float depth = SampleSceneDepth(scrPos);\r\n                depth = LinearEyeDepth(depth);\r\n                float surfaceDepth = i.scrPos.w;\r\n                float depthDiffer = depth - surfaceDepth;\r\n                float2 uvOffset = normalWS.xz * _RefractionStrength * saturate(depthDiffer);\r\n                float2 offsetPos = scrPos + uvOffset;\r\n                float offsetPosDepth = SampleSceneDepth(offsetPos);\r\n                offsetPosDepth = LinearEyeDepth(offsetPosDepth);\r\n                offsetPos = scrPos + uvOffset * step(surfaceDepth, offsetPosDepth);\r\n                float4 refractCol = tex2D(_CameraOpaqueTexture,offsetPos);\r\n                float depthFactor = depth \/ surfaceDepth;\r\n                float3 underPos = (i.positionWS - GetCameraPositionWS()) * depthFactor + GetCameraPositionWS();\r\n                float2 causticSampler = (underPos.xy + underPos.xz + underPos.yz) \/ 100 * _CausticTex_ST.xy;\r\n                float4 caustic1 = tex2D(_CausticTex, causticSampler + _Caustics_Speed.xy * _Time.y\/30);\r\n                float4 caustic2 = tex2D(_CausticTex, causticSampler + _Caustics_Speed.zw * _Time.y\/30); \r\n                float4 caustic = min(caustic1, caustic2);\r\n                \r\n                \/\/------------fog-------------\r\n                float offsetDepthDiffer = surfaceDepth > offsetPosDepth ? depthDiffer: offsetPosDepth - surfaceDepth;\r\n                float fogFactor = saturate(1 - exp(-offsetDepthDiffer * _FogDensity \/ 10)) * _shadowAttenuation;\r\n                float4 waterCol = lerp(_WaterFogColor, _BaseColor, fogFactor);\r\n                refractCol = lerp(waterCol, waterCol * refractCol, saturate(fogFactor));\r\n                refractCol += caustic * pow((1 - saturate(fogFactor)), 10);\r\n\r\n                \/\/------------specular----------\r\n                float3 halfDir = normalize(viewDirectionWS + normalize(_WorldSpaceLightPos0.xyz));\r\n                float3 specular = Highlights(i.positionWS, _Shininess, normalWS, viewDirectionWS);\r\n                specular *= _shadowAttenuation;\r\n\r\n                \/\/------------SSS---------------\r\n                float SSSValue = SubsurfaceScattering(viewDirectionWS, _WorldSpaceLightPos0.xyz, normalWS, _FrontSubsurfaceDistortion,\r\n                _BackSubsurfaceDistortion, _FrontSSSIntensity, saturate(i.heightOS - _HeightCorrection));\r\n                SSSValue *= _shadowAttenuation;\r\n                float fresnel = CalculateFresnel(viewDirectionWS, normalWS);\r\n                float4 scatterCol = lerp(refractCol, reflectCol, saturate(fresnel));\r\n                \r\n                float3 shading = scatterCol.rgb + specular + SSSValue * _LightColor0.rgb;\r\n\r\n                \/\/------------Foam------------------\r\n                float foamOffset = tex2D(_FoamNoiseTex, i.uv * _FoamNoiseTex_ST.xy + _Time.y).x;\r\n                shading = lerp(shading, float3(0.8, 0.8, 0.8), pow(saturate(_FoamIntensity * foamOffset -depthDiffer) * 2, 3) * saturate(depthDiffer));\r\n                \/\/shading = MixFog(shading.rgb, i.fogFactor);\r\n                \/\/ sample the texture\r\n                fixed4 col = tex2D(_MainTex, i.uv);\r\n                \/\/ apply fog\r\n                \/\/UNITY_APPLY_FOG(i.fogCoord, col);\r\n                return (shading.rgb,1);\r\n            }\r\n            ENDCG\r\n        }\r\n    }\r\n}\r\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-849","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/meecarlo.com\/old\/wp-json\/wp\/v2\/posts\/849","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/meecarlo.com\/old\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/meecarlo.com\/old\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/meecarlo.com\/old\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/meecarlo.com\/old\/wp-json\/wp\/v2\/comments?post=849"}],"version-history":[{"count":3,"href":"https:\/\/meecarlo.com\/old\/wp-json\/wp\/v2\/posts\/849\/revisions"}],"predecessor-version":[{"id":852,"href":"https:\/\/meecarlo.com\/old\/wp-json\/wp\/v2\/posts\/849\/revisions\/852"}],"wp:attachment":[{"href":"https:\/\/meecarlo.com\/old\/wp-json\/wp\/v2\/media?parent=849"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/meecarlo.com\/old\/wp-json\/wp\/v2\/categories?post=849"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/meecarlo.com\/old\/wp-json\/wp\/v2\/tags?post=849"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}