361 lines
9.4 KiB
Plaintext
361 lines
9.4 KiB
Plaintext
|
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"
|
||
|
}
|