361 lines
9.4 KiB
Plaintext
Raw Normal View History

2024-02-19 21:00:36 +03:00
Shader "Nature/OceanAdvanced"
{
Properties
{
_BaseColor ("Base color", COLOR) = ( .54, .95, .99, 0.5)
_WaterColor ("Water color", COLOR) = ( .54, .95, .99, 0.5)
_ReflectionColor ("Reflection color", COLOR) = ( .54, .95, .99, 0.5)
_SpecularColor ("Specular color", COLOR) = ( .72, .72, .72, 1)
[NoScaleOffset] _Foam ("Foam texture", 2D) = "white" {}
[HideInInspector] world_light_dir("", VECTOR) = (0.0, 1.0, 0.8, 0.0)
}
CGINCLUDE
#include "UnityCG.cginc"
uniform float4 _BaseColor;
uniform float4 _WaterColor;
uniform float4 _ReflectionColor;
uniform float4 _SpecularColor;
#define NB_WAVE 5
float4 waves_p[NB_WAVE];
float4 waves_d[NB_WAVE];
#define NB_INTERACTIONS 64
#define WAVE_DURATION 4.0
#define WAVE_SPEED 3.0
#define MAX_WAVE_AMP 0.5
float4 interactions[NB_INTERACTIONS];
uniform float4 world_light_dir;
uniform float4 sun_color;
uniform sampler2D _Foam;
uniform sampler2D _RefractionTex;
uniform sampler2D _CameraDepthTexture;
uniform sampler2D _CameraDepthNormalsTexture;
#define PI 3.14159234
float evaluateWave(float4 wave_param, float4 wave_dir, float2 pos, float t)
{
return wave_param.y * sin( dot(wave_dir.xy, pos) * wave_param.x + t * wave_param.z);
}
float get_water_height(float3 p)
{
float height = 0.0;
for(int i = 0; i < NB_WAVE; i++)
height += evaluateWave(waves_p[i], waves_d[i], p.xz, _Time.y);
return height;
}
float3 get_water_normal(float3 a)
{
const float eps = 0.01;
float3 b = a + float3(eps, 0.0, 0.0);
float3 c = a + float3(0.0, 0.0, eps);
a.y = get_water_height(a);
b.y = get_water_height(b);
c.y = get_water_height(c);
float3 n = normalize(cross(c - a, b - a));
return n;
}
float hash(float2 p )
{
float h = dot(p,float2(127.1,311.7));
return frac(sin(h)*43758.5453123);
}
float noise2(in float2 p )
{
float2 i = floor(p);
float2 f = frac(p);
float2 u = f*f*(3.0-2.0*f);
return -1.0+2.0 * lerp( lerp( hash( i + float2(0.0,0.0) ),
hash( i + float2(1.0,0.0) ), u.x),
lerp( hash( i + float2(0.0,1.0) ),
hash( i + float2(1.0,1.0) ), u.x), u.y);
}
float sea_octave(float2 uv, float choppy)
{
uv += noise2(uv);
float2 wv = 1.0 - abs(sin(uv));
float2 swv = abs(cos(uv));
wv = lerp(wv,swv,wv);
return pow(1.0 - pow(wv.x * wv.y,0.65),choppy);
}
float map_detailed(float3 p)
{
float freq = 0.16;
float amp = 0.6;
float choppy = 4.0;
float2 uv = p.xz;
uv.x *= 0.75;
float d, h = 0.0;
for(int i = 0; i < 5; i++)
{
d = sea_octave((uv + _Time.yy) * freq, choppy);
d += sea_octave((uv - _Time.yy) * freq, choppy);
h += d * amp;
uv = float2(uv.x * 1.6 + 1.2 * uv.y, uv.x * -1.2 + 1.6 * uv.y);
freq *= 1.9;
amp *= 0.22;
choppy = lerp(choppy,1.0,0.2);
}
for (int j = 0; j < NB_INTERACTIONS; j++)
{
half dist = distance(p.xz, interactions[j].xy);
half elapsed = (_Time.y - interactions[j].w);
half computed_distance = elapsed * WAVE_SPEED;
half power = 1.0 - saturate(pow(abs(computed_distance - dist), 2.0) * 0.3);
power *= 1.0 - saturate(elapsed / WAVE_DURATION);
dist += 2.0;
p.y += power * interactions[j].z;
}
return p.y - h;
}
float map(float3 p)
{
float freq = 0.16;
float amp = 0.6;
float choppy = 4.0;
float2 uv = p.xz;
uv.x *= 0.75;
float d, h = 0.0;
for(int i = 0; i < 3; i++)
{
d = sea_octave((uv + _Time.yy) * freq, choppy);
d += sea_octave((uv - _Time.yy) * freq, choppy);
h += d * amp;
uv = float2(uv.x * 1.6 + 1.2 * uv.y, uv.x * -1.2 + 1.6 * uv.y);
freq *= 1.9;
amp *= 0.22;
choppy = lerp(choppy,1.0,0.2);
}
return p.y - h;
}
float3 get_detailed_normal(float3 a, float eps)
{
float3 b = a + float3(eps, 0.0, 0.0);
float3 c = a + float3(0.0, 0.0, eps);
a.y = map_detailed(a);
b.y = map_detailed(b);
c.y = map_detailed(c);
float3 n = normalize(cross(b - a, c - a));
n.y *= -1;
return n;
}
float3 getSkyColor(float3 e)
{
e.y = max(e.y, 0.0);
return float3(pow(1.0 - e.y,2.0), 1.0 - e.y, 0.6 + (1.0 - e.y) * 0.4);
}
float diffuse(float3 n,float3 l,float p)
{
return pow(dot(n,l) * 0.4 + 0.6,p);
}
float specular(float3 n,float3 l,float3 e,float s)
{
float nrm = (s + 8.0) / (3.1415 * 8.0);
return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
}
inline void ComputeScreenAndGrabPassPos (float4 pos, out float4 screenPos, out float4 grabPassPos)
{
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0f;
#endif
screenPos = ComputeScreenPos(pos);
grabPassPos.xy = ( float2( pos.x, pos.y*scale ) + pos.w ) * 0.5;
grabPassPos.zw = pos.zw;
}
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 normal : NORMAL;
float3 world_position : TEXCOORD0;
float4 ref : TEXCOORD1;
float4 grabPassPos : TEXCOORD2;
UNITY_FOG_COORDS(5)
};
v2f vert(appdata v)
{
v2f o;
float4 world_position = mul(unity_ObjectToWorld, v.vertex);
world_position.y = get_water_height(world_position.xyz);
float interactive = 0.0;
for (int i = 0; i < NB_INTERACTIONS; i++)
{
half dist = distance(world_position.xz, interactions[i].xy);
half elapsed = (_Time.y - interactions[i].w);
half computed_distance = elapsed * WAVE_SPEED;
half power = 1.0 - saturate(pow(abs(computed_distance - dist), 2.0) * 0.3);
power *= 1.0 - saturate(elapsed / WAVE_DURATION);
dist += 2.0;
interactive += power * interactions[i].z;
}
world_position.y += clamp(interactive, -MAX_WAVE_AMP, MAX_WAVE_AMP);
o.world_position = world_position;
o.normal = get_water_normal(world_position.xyz);
o.pos = mul(UNITY_MATRIX_VP, world_position);
ComputeScreenAndGrabPassPos(o.pos, o.ref, o.grabPassPos);
UNITY_TRANSFER_FOG(o,o.pos);
return o;
}
#define REFLECTION
#define FOAM
#define SPECULAR
#define REFRACTION
half4 frag( v2f i ) : SV_Target
{
float3 eye_vector = i.world_position.xyz - _WorldSpaceCameraPos;
float eye_distance = length(eye_vector);
float3 eye = normalize(eye_vector);
half3 detail_normal = get_detailed_normal(i.world_position, 0.01 * pow(length(eye_vector), 0.8));
half3 vertex_normal = i.normal;
half3 normal = normalize(detail_normal * 1.0 + vertex_normal * 0.0);
float depth = LinearEyeDepth(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.ref)).r);
half4 distort = half4(i.normal.xz * 0.5 + detail_normal.xz * 0.6, 0.0, 0.0);
distort *= pow(saturate((depth - i.ref.z) * 0.3), 2.0);
float sceneZ = LinearEyeDepth(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.ref + distort * 0.2)).r);
float objectZ = i.ref.z;
float depthFactor = 1.0 - saturate(abs(sceneZ - objectZ) / 4.0);
float3 light_direction = normalize(world_light_dir);
half4 baseColor;
baseColor.a = 1.0;
//baseColor.rgb = getSeaColor(i.world_position, normal, normalize(light_direction), normalize(eye_vector), eye_vector);
#ifdef REFLECTION
float3 l = normalize(light_direction);
float fresnel = clamp(1.0 - pow(dot(normal,-eye), 1.0), 0.0, 1.0);
fresnel = pow(fresnel,3.0) * 0.65;
fresnel = pow(fresnel, 0.8) * 0.8;
float3 reflected = getSkyColor(reflect(eye,normal)) * _ReflectionColor;
/* SSR test */
#ifdef SSR
half4 refl = i.ref + distort;
float3 decodedNormal;
float decodedDepth;
DecodeDepthNormal( tex2D( _CameraDepthNormalsTexture, i.uv), decodedDepth, normal);
float4 pixelPosition = float4(i.cameraRay * decodedDepth, 0.0);
//float3 reflected = tex2Dproj(_RefractionTex, UNITY_PROJ_COORD(pixelPosition)) * _ReflectionColor;
#endif
float3 refracted = _BaseColor + diffuse(normal, l, 80.0) * _WaterColor * 0.12;
baseColor.rgb = lerp( refracted, reflected, fresnel);
#endif
#ifdef REFRACTION
half3 refraction = tex2Dproj(_RefractionTex, UNITY_PROJ_COORD(i.grabPassPos + distort));
refraction *= lerp(_ReflectionColor, _BaseColor, 1.0 - depthFactor * 2.0);
baseColor.a = 1.0 - (saturate(depthFactor * 2.0) * saturate(1.2 - 0.6));
#endif
/* Possible depth color */
float atten = max(1.0 - dot(eye, eye) * 0.001, 0.0);
baseColor.rgb += _WaterColor * (i.world_position.y + 0.6) * 0.18 * atten;
#ifdef SPECULAR
float spec = specular(vertex_normal * 0.2 + detail_normal * 0.8, l, eye, 60.0);
baseColor.rgb += sun_color * spec;
#endif
#ifdef FOAM
half3 foamColor = tex2D(_Foam, i.world_position.xz * 0.1 + _Time.xx * 0.5 + distort).rgb;
//baseColor.rgb += foamColor * smoothstep(0.2, 1.5, depthFactor);
baseColor.a += foamColor.r * 0.05;
float wave_foam = clamp(smoothstep(-0.1, 1.0, 1.0 - detail_normal.y), 0.0, 0.5);
baseColor.a += wave_foam;
baseColor = saturate(baseColor);
baseColor.rgb += foamColor * clamp(wave_foam + smoothstep(0.2, 1.5, depthFactor), 0.0, 0.5);
#endif
UNITY_APPLY_FOG(i.fogCoord, baseColor);
baseColor = saturate(baseColor);
baseColor.rgb = lerp(refraction.rgb, baseColor.rgb, clamp(baseColor.a, 0.0, 0.8));
baseColor.a = 1.0;
return saturate(baseColor);
}
ENDCG
Subshader
{
Tags {"RenderType"="Transparent" "Queue"="Transparent"}
Lod 300
//ColorMask RGBA
GrabPass { "_RefractionTex" }
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
//ZTest LEqual
//ZWrite Off
//Cull Off
CGPROGRAM
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#pragma multi_compile_fwdbase
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
ENDCG
}
}
Fallback "Transparent/Diffuse"
}