Skip to content

Instantly share code, notes, and snippets.

@johans2
Last active February 12, 2020 09:56
Show Gist options
  • Save johans2/7e1cb4efcf170aab6d29ec81d7f4bf51 to your computer and use it in GitHub Desktop.
Save johans2/7e1cb4efcf170aab6d29ec81d7f4bf51 to your computer and use it in GitHub Desktop.
// Written by: Johan Svensson (https://medium.com/dotcrossdot).
Shader "DotCrossDot/Water" {
Properties{
// Color
_Color("Color", Color) = (0,0,1,1)
_SmoothNess("SmoothNess", Range(0.0,1.0)) = 0
_Metallic("Reflectivity", Range(0.0,1.0)) = 0
_WaveFoamDir("Wave foam direction", Vector) = (0,0,0,0)
// Distortion (normals and height maps)
[Header(Distortions 1)]
_NormalMap1("Normalmap 1", 2D) = "white" {}
_NormalMapMoveDir1("Normalmap 1 move dir", Vector) = (0,0,0,0)
_NormalMapMoveSpeed1("Normalmap 1 move speed", Float) = 0
_Heightmap("Height map", 2D) = "black" {}
[Header(Distortions 2)]
_NormalMap2("Normalmap 2", 2D) = "white" {}
_NormalMapMoveDir2("Normalmap 2 move dir", Vector) = (0,0,0,0)
_NormalMapMoveSpeed2("Normalmap 2 move speed", Float) = 0
_Heightmap2("Height map", 2D) = "black" {}
[Header(Distortion settings)]
_NormalMapBias("Normalmap Strength", Range(0.0,1.0)) = 0.5
_HeightmapStrength("Heightmap strength", Range(0,5)) = 0
_HeightmapFoamColor("Heightmap foam color", Color) = (1,1,1,1)
_HeightMapFoamStrength("Heightmap foam strength", Range(0,2)) = 1
// Fog
[Header(Water fog)]
_WaterFogColor("Water Fog Color", Color) = (0, 0, 0, 0)
_WaterFogDensity("Water Fog Density", Range(0, 10)) = 0.15
// Refraction
[Header(Refraction)]
_RefractionStrength("Refraction Strength", Range(0, 1)) = 0.25
// Subsurface scattering
[Header(Subsurface scattering)]
_SSSPower("Power", Float) = 0
// Wave Crest foam
[Header(Wave crest foam)]
_FoamSpread("Foam Scale", Range(0.1, 3.0)) = 2.43
// Intersection foam
[Header(Intersection foam)]
_IntersectionFoamDensity("Intersection Foam Range", Range(0, 10)) = 0.15
_IntersectionFoamRamp("Intersection Foam Ramp", 2D) = "black" {}
_IntersectionFoamColor("Intersection foam Color", Color) = (1,1,1,1)
// Vertex waves
[Header(Base Wave)]
_WaveLength1("Wavelength", Float) = 0.1
_Amplitude1("Amplitude", Float) = 0.001
_Speed1("Speed", Float) = 1
_DirectionX1("Direction X", Range(-1,1)) = 1
_DirectionY1("Direction Y", Range(-1,1)) = 1
_Steepness1("Steepness", Range(0,10)) = 0.1
_FadeSpeed1("FadeSpeed", Float) = 1.0
[Header(Additional Waves)]
[Header(Wave 2)]
[Toggle(WAVE2)] _Wave2Enabled("Enabled", Float) = 0
_WaveLength2("Wavelength", Float) = 0.1
_Amplitude2("Amplitude", Float) = 0.001
_Speed2("Speed", Float) = 1
_DirectionX2("Direction X", Range(-1,1)) = 1
_DirectionY2("Direction Y", Range(-1,1)) = 1
_Steepness2("Steepness", Range(0,10)) = 0.1
_FadeSpeed2("FadeSpeed", Float) = 1.0
[Header(Wave 3)]
[Toggle(WAVE3)] _Wave3Enabled("Enabled", Float) = 0
_WaveLength3("Wavelength", Float) = 0.1
_Amplitude3("Amplitude", Float) = 0.001
_Speed3("Speed", Float) = 1
_DirectionX3("Direction X", Range(-1,1)) = 1
_DirectionY3("Direction Y", Range(-1,1)) = 1
_Steepness3("Steepness", Range(0,10)) = 0.1
_FadeSpeed3("FadeSpeed", Float) = 1.0
[Header(Wave 4)]
[Toggle(WAVE4)] _Wave4Enabled("Enabled", Float) = 0
_WaveLength4("Wavelength", Float) = 0.1
_Amplitude4("Amplitude", Float) = 0.001
_Speed4("Speed", Float) = 1
_DirectionX4("Direction X", Range(-1,1)) = 1
_DirectionY4("Direction Y", Range(-1,1)) = 1
_Steepness4("Steepness", Range(0,10)) = 0.1
_FadeSpeed4("FadeSpeed", Float) = 1.0
[Header(Wave 5)]
[Toggle(WAVE5)] _Wave5Enabled("Enabled", Float) = 0
_WaveLength5("Wavelength", Float) = 0.1
_Amplitude5("Amplitude", Float) = 0.001
_Speed5("Speed", Float) = 1
_DirectionX5("Direction X", Range(-1,1)) = 1
_DirectionY5("Direction Y", Range(-1,1)) = 1
_Steepness5("Steepness", Range(0,10)) = 0.1
_FadeSpeed5("FadeSpeed", Float) = 1.0
}
SubShader{
// ------- PASS 1 ---------------
ZWrite on
Cull back
Colormask 0
Lighting Off
CGPROGRAM
#pragma surface surf Standard vertex:vert nometa
#include "UnityCG.cginc"
#include "WaterIncludes.cginc"
#pragma shader_feature WAVE2
#pragma shader_feature WAVE3
#pragma shader_feature WAVE4
#pragma shader_feature WAVE5
struct Input {
float2 uv_MainTex;
};
// Height map
sampler2D _Heightmap;
sampler2D _Heightmap2;
float _HeightmapStrength;
half4 _NormalMapMoveDir1;
half4 _NormalMapMoveDir2;
half _NormalMapMoveSpeed1;
half _NormalMapMoveSpeed2;
void vert(inout appdata_full v) {
float3 worldPos = mul(unity_ObjectToWorld, v.vertex);
float3 wavePointSum = worldPos + WavePointSum(worldPos).xyz;
// Add heightmap value to pos.y
float heightAdd1 = tex2Dlod(_Heightmap, float4(v.texcoord.xy + _NormalMapMoveDir1.xy * _NormalMapMoveSpeed1 * _Time.x, 0, 0)).r;
float heightAdd2 = tex2Dlod(_Heightmap2, float4(v.texcoord.xy + _NormalMapMoveDir2.xy * _NormalMapMoveSpeed2 * _Time.x, 0, 0)).r;
heightAdd1 = (heightAdd1 - 0.5) * 2;
heightAdd2 = (heightAdd2 - 0.5) * 2;
float heightAddCombined = (heightAdd1 + heightAdd2) / 2;
wavePointSum.y += (heightAddCombined * _HeightmapStrength);
// Final vertex output
v.vertex.xyz = mul(unity_WorldToObject, float4(wavePointSum, 1));
}
void surf(Input IN, inout SurfaceOutputStandard o) { }
ENDCG
// ------- END PASS 1 ---------------
GrabPass{ "_WaterBackground" }
// ------- PASS 2 ---------------
Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" }
ZWrite off
Cull back
Blend SrcAlpha OneMinusSrcAlpha
Colormask RGBA
CGPROGRAM
#pragma surface surf StandardTranslucent vertex:vert alpha:fade finalcolor:ResetAlpha nometa novertexlights noforwardadd
#include "UnityCG.cginc"
#include "UnityPBSLighting.cginc"
#include "WaterIncludes.cginc"
#pragma target 3.0
#pragma shader_feature WAVE2
#pragma shader_feature WAVE3
#pragma shader_feature WAVE4
#pragma shader_feature WAVE5
struct Input {
float2 uv_NormalMap1;
float2 uv_NormalMap2;
float4 screenPos;
float crestFactor;
float3 worldDirNormal;
};
// Normal maps
sampler2D _NormalMap1;
sampler2D _NormalMap2;
half4 _NormalMapMoveDir1;
half _NormalMapMoveSpeed1;
half4 _NormalMapMoveDir2;
half _NormalMapMoveSpeed2;
half _NormalMapBias;
// Color
fixed4 _Color;
fixed4 _SSSColor;
// Other
half _SmoothNess;
half _Metallic;
fixed4 _WaveFoamDir;
// SubSurface Scattering
half _SSSPower;
// Height map
sampler2D _Heightmap;
sampler2D _Heightmap2;
half _HeightmapStrength;
fixed3 _HeightmapFoamColor;
half _HeightMapFoamStrength;
void vert(inout appdata_full v, out Input o) {
UNITY_INITIALIZE_OUTPUT(Input, o);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex);
float4 wavePointSum = WavePointSum(worldPos);
float3 pos = worldPos + wavePointSum.xyz;
// This is to avoid z fighting between the two passes. Can probably be done in a better way.
pos.y += 0.001;
float heightAdd1 = tex2Dlod(_Heightmap, float4(v.texcoord.xy + _NormalMapMoveDir1.xy * _NormalMapMoveSpeed1 * _Time.x, 0, 0)).r;
float heightAdd2 = tex2Dlod(_Heightmap2, float4(v.texcoord.xy + _NormalMapMoveDir2.xy * _NormalMapMoveSpeed2 * _Time.x, 0, 0)).r;
heightAdd1 = (heightAdd1 - 0.5) * 2;
heightAdd2 = (heightAdd2 - 0.5) * 2;
float heightAddCombined = (heightAdd1 + heightAdd2) / 2;
pos.y += (heightAddCombined * _HeightmapStrength);
float3 waveNormalSum = WaveNormalSum(pos);
o.crestFactor = wavePointSum.w;
o.worldDirNormal = waveNormalSum.xyz;
// Final vertex output
v.vertex = mul(unity_WorldToObject, float4(pos,1));
v.normal = normalize(waveNormalSum);
}
inline fixed4 LightingStandardTranslucent(SurfaceOutputStandard s, fixed3 viewDir, UnityGI gi)
{
// Original colour
fixed4 pbr = LightingStandard(s, viewDir, gi);
// Inverse Normal dot Light
float NdotL = 1 - max(0, dot(gi.light.dir, s.Normal));
// ViewDir dot Normal
float VdotN = max(0, dot(viewDir, s.Normal));
// ViewDir dot LightDir
float VdotL = max(0, dot(normalize(-_WorldSpaceCameraPos.xyz), gi.light.dir));
float SSS = NdotL * VdotN * VdotL * _SSSPower;
// Final add
pbr.rgb = pbr.rgb + SSS * _Color;
return pbr;
}
void LightingStandardTranslucent_GI(SurfaceOutputStandard s, UnityGIInput data, inout UnityGI gi)
{
LightingStandard_GI(s, data, gi);
}
void ResetAlpha(Input IN, SurfaceOutputStandard o, inout fixed4 color) {
color.a = 1;
}
void surf(Input IN, inout SurfaceOutputStandard o) {
float noFoam = saturate(dot(IN.worldDirNormal, _WaveFoamDir));
// ---------- Normal maps ----------
float3 waterNormal1 = normalize(UnpackNormal(tex2D(_NormalMap1, IN.uv_NormalMap1 + _NormalMapMoveDir1.xy * _NormalMapMoveSpeed1 * _Time.x)));
float3 waterNormal2 = normalize(UnpackNormal(tex2D(_NormalMap2, IN.uv_NormalMap2 + _NormalMapMoveDir2.xy * _NormalMapMoveSpeed2 * _Time.x)));
float3 totalWaterNormal = normalize(float3(waterNormal1.xy + waterNormal2.xy, waterNormal1.z));
totalWaterNormal.xy *= _NormalMapBias;
o.Normal = totalWaterNormal;
// ---------- Height map foam ----------
float heightMapAdd1 = pow(tex2D(_Heightmap, IN.uv_NormalMap1 + _NormalMapMoveDir1.xy * _NormalMapMoveSpeed1 * _Time.x).r, 4);
float heightMapAdd2 = pow(tex2D(_Heightmap2, IN.uv_NormalMap2 + _NormalMapMoveDir2.xy * _NormalMapMoveSpeed2 * _Time.x).r, 4);
float totalHeightAdd = ((heightMapAdd1 + heightMapAdd2) / 2) * _HeightMapFoamStrength;
// ---------- Total water foam ----------
float3 foam = ((totalHeightAdd + IN.crestFactor) / 2) * (1 - noFoam);
// ---------- Alpha ----------
float alpha = saturate(_Color.a + foam);
// ---------- Refraction, fog and intersection ----------
float3 colorBelowWater = ColorBelowWater(IN.screenPos, o.Normal);
o.Albedo = _Color + foam;
o.Smoothness = saturate( _SmoothNess - foam);
o.Metallic = _Metallic;
o.Alpha = alpha;
o.Emission = colorBelowWater * (1 - alpha);
}
ENDCG
}
}
// Written by: Johan Svensson (https://medium.com/dotcrossdot).
// Written by: Johan Svensson (https://medium.com/dotcrossdot).
Shader "DotCrossDot/Water simple" {
Properties{
// Color
_Color("Color", Color) = (0,0,1,1)
_SmoothNess("SmoothNess", Range(0.0,1.0)) = 0
_Metallic("Reflectivity", Range(0.0,1.0)) = 0
_WaveFoamDir("Wave foam direction", Vector) = (0,0,0,0)
// Distortion (normals and height maps)
[Header(Distortions 1)]
_NormalMap1("Normalmap 1", 2D) = "white" {}
_NormalMapMoveDir1("Normalmap 1 move dir", Vector) = (0,0,0,0)
_NormalMapMoveSpeed1("Normalmap 1 move speed", Float) = 0
_Heightmap("Height map", 2D) = "black" {}
[Header(Distortions 2)]
_NormalMap2("Normalmap 2", 2D) = "white" {}
_NormalMapMoveDir2("Normalmap 2 move dir", Vector) = (0,0,0,0)
_NormalMapMoveSpeed2("Normalmap 2 move speed", Float) = 0
_Heightmap2("Height map", 2D) = "black" {}
[Header(Distortion settings)]
_NormalMapBias("Normalmap Strength", Range(0.0,1.0)) = 0.5
_HeightmapStrength("Heightmap strength", Range(0,5)) = 0
_HeightmapFoamColor("Heightmap foam color", Color) = (1,1,1,1)
_HeightMapFoamStrength("Heightmap foam strength", Range(0,2)) = 1
// Fog
[Header(Water fog)]
_WaterFogColor("Water Fog Color", Color) = (0, 0, 0, 0)
_WaterFogDensity("Water Fog Density", Range(0, 10)) = 0.15
// Refraction
[Header(Refraction)]
_RefractionStrength("Refraction Strength", Range(0, 1)) = 0.25
// Subsurface scattering
[Header(Subsurface scattering)]
_SSSPower("Power", Float) = 0
// Wave Crest foam
[Header(Wave crest foam)]
_FoamSpread("Foam Scale", Range(0.1, 3.0)) = 2.43
// Intersection foam
[Header(Intersection foam)]
_IntersectionFoamDensity("Intersection Foam Range", Range(0, 10)) = 0.15
_IntersectionFoamRamp("Intersection Foam Ramp", 2D) = "black" {}
_IntersectionFoamColor("Intersection foam Color", Color) = (1,1,1,1)
// Vertex waves
[Header(Base Wave)]
_WaveLength1("Wavelength", Float) = 0.1
_Amplitude1("Amplitude", Float) = 0.001
_Speed1("Speed", Float) = 1
_DirectionX1("Direction X", Range(-1,1)) = 1
_DirectionY1("Direction Y", Range(-1,1)) = 1
_Steepness1("Steepness", Range(0,10)) = 0.1
_FadeSpeed1("FadeSpeed", Float) = 1.0
[Header(Additional Waves)]
[Header(Wave 2)]
[Toggle(WAVE2)] _Wave2Enabled("Enabled", Float) = 0
_WaveLength2("Wavelength", Float) = 0.1
_Amplitude2("Amplitude", Float) = 0.001
_Speed2("Speed", Float) = 1
_DirectionX2("Direction X", Range(-1,1)) = 1
_DirectionY2("Direction Y", Range(-1,1)) = 1
_Steepness2("Steepness", Range(0,10)) = 0.1
_FadeSpeed2("FadeSpeed", Float) = 1.0
[Header(Wave 3)]
[Toggle(WAVE3)] _Wave3Enabled("Enabled", Float) = 0
_WaveLength3("Wavelength", Float) = 0.1
_Amplitude3("Amplitude", Float) = 0.001
_Speed3("Speed", Float) = 1
_DirectionX3("Direction X", Range(-1,1)) = 1
_DirectionY3("Direction Y", Range(-1,1)) = 1
_Steepness3("Steepness", Range(0,10)) = 0.1
_FadeSpeed3("FadeSpeed", Float) = 1.0
[Header(Wave 4)]
[Toggle(WAVE4)] _Wave4Enabled("Enabled", Float) = 0
_WaveLength4("Wavelength", Float) = 0.1
_Amplitude4("Amplitude", Float) = 0.001
_Speed4("Speed", Float) = 1
_DirectionX4("Direction X", Range(-1,1)) = 1
_DirectionY4("Direction Y", Range(-1,1)) = 1
_Steepness4("Steepness", Range(0,10)) = 0.1
_FadeSpeed4("FadeSpeed", Float) = 1.0
[Header(Wave 5)]
[Toggle(WAVE5)] _Wave5Enabled("Enabled", Float) = 0
_WaveLength5("Wavelength", Float) = 0.1
_Amplitude5("Amplitude", Float) = 0.001
_Speed5("Speed", Float) = 1
_DirectionX5("Direction X", Range(-1,1)) = 1
_DirectionY5("Direction Y", Range(-1,1)) = 1
_Steepness5("Steepness", Range(0,10)) = 0.1
_FadeSpeed5("FadeSpeed", Float) = 1.0
}
SubShader{
// ------- PASS 2 ---------------
Tags{"RenderType" = "Opaque" }
ZWrite on
Cull back
Blend SrcAlpha OneMinusSrcAlpha
Colormask RGBA
CGPROGRAM
#pragma surface surf StandardTranslucent vertex:vert nometa novertexlights noforwardadd
#include "UnityCG.cginc"
#include "UnityPBSLighting.cginc"
#include "WaterIncludes.cginc"
#pragma target 3.0
#pragma shader_feature WAVE2
#pragma shader_feature WAVE3
#pragma shader_feature WAVE4
#pragma shader_feature WAVE5
struct Input {
float2 uv_NormalMap1;
float2 uv_NormalMap2;
float4 screenPos;
float crestFactor;
float3 worldDirNormal;
};
// Normal maps
sampler2D _NormalMap1;
sampler2D _NormalMap2;
half4 _NormalMapMoveDir1;
half _NormalMapMoveSpeed1;
half4 _NormalMapMoveDir2;
half _NormalMapMoveSpeed2;
half _NormalMapBias;
// Color
fixed4 _Color;
fixed4 _SSSColor;
// Other
half _SmoothNess;
half _Metallic;
fixed4 _WaveFoamDir;
// SubSurface Scattering
half _SSSPower;
// Height map
sampler2D _Heightmap;
sampler2D _Heightmap2;
half _HeightmapStrength;
fixed3 _HeightmapFoamColor;
half _HeightMapFoamStrength;
void vert(inout appdata_full v, out Input o) {
UNITY_INITIALIZE_OUTPUT(Input, o);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex);
float4 wavePointSum = WavePointSum(worldPos);
float3 pos = worldPos + wavePointSum.xyz;
// This is to avoid z fighting between the two passes. Can probably be done in a better way.
pos.y += 0.001;
float heightAdd1 = tex2Dlod(_Heightmap, float4(v.texcoord.xy + _NormalMapMoveDir1.xy * _NormalMapMoveSpeed1 * _Time.x, 0, 0)).r;
float heightAdd2 = tex2Dlod(_Heightmap2, float4(v.texcoord.xy + _NormalMapMoveDir2.xy * _NormalMapMoveSpeed2 * _Time.x, 0, 0)).r;
heightAdd1 = (heightAdd1 - 0.5) * 2;
heightAdd2 = (heightAdd2 - 0.5) * 2;
float heightAddCombined = (heightAdd1 + heightAdd2) / 2;
pos.y += (heightAddCombined * _HeightmapStrength);
float3 waveNormalSum = WaveNormalSum(pos);
o.crestFactor = wavePointSum.w;
o.worldDirNormal = waveNormalSum.xyz;
// Final vertex output
v.vertex = mul(unity_WorldToObject, float4(pos,1));
v.normal = normalize(waveNormalSum);
}
inline fixed4 LightingStandardTranslucent(SurfaceOutputStandard s, fixed3 viewDir, UnityGI gi)
{
// Original colour
fixed4 pbr = LightingStandard(s, viewDir, gi);
// Inverse Normal dot Light
float NdotL = 1 - max(0, dot(gi.light.dir, s.Normal));
// ViewDir dot Normal
float VdotN = max(0, dot(viewDir, s.Normal));
// ViewDir dot LightDir
float VdotL = max(0, dot(normalize(-_WorldSpaceCameraPos.xyz), gi.light.dir));
float SSS = NdotL * VdotN * VdotL * _SSSPower;
// Final add
pbr.rgb = pbr.rgb + SSS * _Color;
return pbr;
}
void LightingStandardTranslucent_GI(SurfaceOutputStandard s, UnityGIInput data, inout UnityGI gi)
{
LightingStandard_GI(s, data, gi);
}
void surf(Input IN, inout SurfaceOutputStandard o) {
float noFoam = saturate(dot(IN.worldDirNormal, _WaveFoamDir));
// ---------- Normal maps ----------
float3 waterNormal1 = normalize(UnpackNormal(tex2D(_NormalMap1, IN.uv_NormalMap1 + _NormalMapMoveDir1.xy * _NormalMapMoveSpeed1 * _Time.x)));
float3 waterNormal2 = normalize(UnpackNormal(tex2D(_NormalMap2, IN.uv_NormalMap2 + _NormalMapMoveDir2.xy * _NormalMapMoveSpeed2 * _Time.x)));
float3 totalWaterNormal = normalize(float3(waterNormal1.xy + waterNormal2.xy, waterNormal1.z));
totalWaterNormal.xy *= _NormalMapBias;
o.Normal = totalWaterNormal;
// ---------- Height map foam ----------
float heightMapAdd1 = pow(tex2D(_Heightmap, IN.uv_NormalMap1 + _NormalMapMoveDir1.xy * _NormalMapMoveSpeed1 * _Time.x).r, 4);
float heightMapAdd2 = pow(tex2D(_Heightmap2, IN.uv_NormalMap2 + _NormalMapMoveDir2.xy * _NormalMapMoveSpeed2 * _Time.x).r, 4);
float totalHeightAdd = ((heightMapAdd1 + heightMapAdd2) / 2) * _HeightMapFoamStrength;
// ---------- Total water foam ----------
float3 foam = ((totalHeightAdd + IN.crestFactor) / 2) * (1 - noFoam);
// ---------- Alpha ----------
float alpha = saturate(_Color.a + foam);
o.Albedo = _Color + foam;
o.Smoothness = saturate( _SmoothNess - foam);
o.Metallic = _Metallic;
o.Alpha = alpha;
}
ENDCG
}
}
// Written by: Johan Svensson (https://medium.com/dotcrossdot).
// Water functions for position, normal and crest at given point
// Gerstner wave function: https://developer.nvidia.com/gpugems/GPUGems/gpugems_ch01.html
float _WaveLength1;
float _Amplitude1;
float _Speed1;
float _DirectionX1;
float _DirectionY1;
float _Steepness1;
float _FadeSpeed1;
float _FoamSpread;
float _FoamSharpness;
sampler2D _CameraDepthTexture;
sampler2D _WaterBackground;
float4 _CameraDepthTexture_TexelSize;
float4 _WaterFogColor;
float _WaterFogDensity;
float _RefractionStrength;
// Intersection foam
half _IntersectionFoamDensity;
sampler2D _IntersectionFoamRamp;
fixed4 _IntersectionFoamColor;
#if WAVE2
float _WaveLength2;
float _Amplitude2;
float _Speed2;
float _DirectionX2;
float _DirectionY2;
float _Steepness2;
float _FadeSpeed2;
#endif
#if WAVE3
float _WaveLength3;
float _Amplitude3;
float _Speed3;
float _DirectionX3;
float _DirectionY3;
float _Steepness3;
float _FadeSpeed3;
#endif
#if WAVE4
float _WaveLength4;
float _Amplitude4;
float _Speed4;
float _DirectionX4;
float _DirectionY4;
float _Steepness4;
float _FadeSpeed4;
#endif
#if WAVE5
float _WaveLength5;
float _Amplitude5;
float _Speed5;
float _DirectionX5;
float _DirectionY5;
float _Steepness5;
float _FadeSpeed5;
#endif
// Returns x,y,z position and w crestFactor (used for foam)
float4 WavePoint(float2 position, float amplitude, float wavelength, float speed, float2 direction, float steepness, float fadeSpeed) {
half frequency = 2 / wavelength;
half phaseConstantSpeed = speed * 2 / wavelength;
half2 normalizedDir = normalize(direction);
half fi = _Time.x * phaseConstantSpeed;
half dirDotPos = dot(normalizedDir, position);
half fade = cos(fadeSpeed * _Time.x) / 2 + 0.5;
amplitude *= fade;
float waveGretsX = steepness * amplitude * normalizedDir.x * cos(frequency * dirDotPos + fi);
float crest = sin(frequency * dirDotPos + fi);
float waveGretsY = amplitude * crest;
float waveGretsZ = steepness * amplitude * normalizedDir.y * cos(frequency * dirDotPos + fi);
float crestFactor = crest * saturate(steepness) * fade;
return float4(waveGretsX, waveGretsY, waveGretsZ, crestFactor);
}
float3 WaveNormal(float3 position, float amplitude, float wavelength, float speed, float2 direction, float steepness) {
half frequency = 2 / wavelength;
half phaseConstantSpeed = speed * 2 / wavelength;
half2 normalizedDir = normalize(direction);
half fi = _Time.x * phaseConstantSpeed;
half dirDotPos = dot(normalizedDir, position.xz);
float WA = frequency * amplitude;
float S = sin(frequency * dirDotPos + fi);
float C = cos(frequency * dirDotPos + fi);
float3 normal = float3 (
normalizedDir.x * WA * C,
min(0.2f,steepness * WA * S),
normalizedDir.y * WA * C
);
return normal;
}
float4 WavePointSum(float3 worldPos) {
float4 wavePointSum = WavePoint(worldPos.xz,
_Amplitude1,
_WaveLength1,
_Speed1,
float2(_DirectionX1, _DirectionY1),
_Steepness1,
_FadeSpeed1);
float totSteepness = _FoamSpread;
#if WAVE2
float4 wave2 = WavePoint(worldPos.xz,
_Amplitude2,
_WaveLength2,
_Speed2,
float2(_DirectionX2, _DirectionY2),
_Steepness2,
_FadeSpeed2);
wavePointSum += wave2;
totSteepness += _FoamSpread;
#endif
#if WAVE3
float4 wave3 = WavePoint(worldPos.xz,
_Amplitude3,
_WaveLength3,
_Speed3,
float2(_DirectionX3, _DirectionY3),
_Steepness3,
_FadeSpeed3);
wavePointSum += wave3;
totSteepness += _FoamSpread;
#endif
#if WAVE4
float4 wave4 = WavePoint(worldPos.xz,
_Amplitude4,
_WaveLength4,
_Speed4,
float2(_DirectionX4, _DirectionY4),
_Steepness4,
_FadeSpeed4);
wavePointSum += wave4;
totSteepness += _FoamSpread;
#endif
#if WAVE5
float4 wave5 = WavePoint(worldPos.xz,
_Amplitude5,
_WaveLength5,
_Speed5,
float2(_DirectionX5, _DirectionY5),
_Steepness5,
_FadeSpeed5);
wavePointSum += wave5;
totSteepness += _FoamSpread;
#endif
wavePointSum.w /= totSteepness;
wavePointSum.w = max(0.01, wavePointSum.w);
return wavePointSum;
}
float3 WaveNormalSum(float3 wavePointSum) {
float3 normalSum = WaveNormal( wavePointSum,
_Amplitude1,
_WaveLength1,
_Speed1,
float2(_DirectionX1, _DirectionY1),
_Steepness1);
#if WAVE2
normalSum += WaveNormal(wavePointSum,
_Amplitude2,
_WaveLength2,
_Speed2,
float2(_DirectionX2, _DirectionY2),
_Steepness2);
#endif
#if WAVE3
normalSum += WaveNormal(wavePointSum,
_Amplitude3,
_WaveLength3,
_Speed3,
float2(_DirectionX3, _DirectionY3),
_Steepness3);
#endif
#if WAVE4
normalSum += WaveNormal(wavePointSum,
_Amplitude4,
_WaveLength4,
_Speed4,
float2(_DirectionX4, _DirectionY4),
_Steepness4);
#endif
#if WAVE5
normalSum += WaveNormal(wavePointSum,
_Amplitude5,
_WaveLength5,
_Speed5,
float2(_DirectionX5, _DirectionY5),
_Steepness5);
#endif
return float3(-normalSum.x, 1 - normalSum.y, -normalSum.z);
}
float2 AlignWithGrabTexel(float2 uv) {
#if UNITY_UV_STARTS_AT_TOP
if (_CameraDepthTexture_TexelSize.y < 0) {
uv.y = 1 - uv.y;
}
#endif
return (floor(uv * _CameraDepthTexture_TexelSize.zw) + 0.5) * abs(_CameraDepthTexture_TexelSize.xy);
}
// Based on https://catlikecoding.com/unity/tutorials/flow/looking-through-water/
float3 ColorBelowWater(float4 screenPos, float3 tangentSpaceNormal) {
float2 uvOffset = tangentSpaceNormal.xy * _RefractionStrength;
uvOffset.y *= _CameraDepthTexture_TexelSize.z * abs(_CameraDepthTexture_TexelSize.y);
float2 uv = AlignWithGrabTexel((screenPos.xy + uvOffset) / screenPos.w);
float backgroundDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv));
float surfaceDepth = UNITY_Z_0_FAR_FROM_CLIPSPACE(screenPos.z);
float depthDifference = backgroundDepth - surfaceDepth;
uvOffset *= saturate(depthDifference);
uv = AlignWithGrabTexel((screenPos.xy + uvOffset) / screenPos.w);
backgroundDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv));
depthDifference = backgroundDepth - surfaceDepth;
// Fog and refraction
float3 backgroundColor = tex2D(_WaterBackground, uv).rgb;
float fogFactor = saturate(exp2(-_WaterFogDensity * depthDifference));
// Intersection foam
float interSectionFoamRange = saturate(exp2(-depthDifference)) ;
float interSectionFoamFactor = tex2D(_IntersectionFoamRamp, float2(interSectionFoamRange, 0));
// Final interpolated color
float3 colorUnderWater = lerp(_WaterFogColor, backgroundColor, fogFactor);
float3 finalColor = colorUnderWater + _IntersectionFoamColor * (interSectionFoamFactor * _IntersectionFoamDensity);
return finalColor;;
}
// Written by: Johan Svensson (https://medium.com/dotcrossdot).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment