Seascape shader

Shadertoy Seascape shader converted to Godot shader

Create a ColorRect node, add a new shader to it and paste the script in the shader script

Original:

https://www.shadertoy.com/view/Ms2SD1

Shader code
// Seascape shader from shadertoy converted to Godot shader
// Original https://www.shadertoy.com/view/Ms2SD1
// Converted by Johan Forsblom a.k.a SolarStrings

shader_type canvas_item;

const int NUM_STEPS = 14;
const float PI	 	= 3.141592;
const float EPSILON	= 0.001;
uniform int AA = 1;
uniform vec4 iMouse = vec4(0,0,0,1);
// sea
const int ITER_GEOMETRY = 6;
const int ITER_FRAGMENT = 9;
const float SEA_HEIGHT = 1.2;
const float SEA_CHOPPY = 6.0;
const float SEA_SPEED = 5.1;
const float SEA_FREQ = 0.10;
const vec3 SEA_BASE = vec3(0.1,0.15,0.19);
const vec3 SEA_WATER_COLOR = vec3(0.1,0.9,0.6)*0.;

const mat2 getoctave_m()
{
	vec2 vector1 = vec2(1.6,1.2);
	vec2 vector2 = vec2(-1.2,1.6);
	return mat2(vector1,vector2);	
} 

float  getSEA_TIME(float time)
{ 
	return (1.0 + time * SEA_SPEED);
}

float getEPSILON_NRM(vec2 screen_pixel_size)
{
	return 1.0 / screen_pixel_size.x;
}

// math
mat3 fromEuler(vec3 ang) {
	vec2 a1 = vec2(sin(ang.x),cos(ang.x));
    vec2 a2 = vec2(sin(ang.y),cos(ang.y));
    vec2 a3 = vec2(sin(ang.z),cos(ang.z));
    mat3 m;
    m[0] = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x);
	m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);
	m[2] = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y);
	return m;
}
float hash( vec2 p ) {
    float h = dot(p,vec2(127.1,311.7));	
    return fract(sin(h)*43758.5453123);
}
float noise( in vec2 p ) {
    vec2 i = floor( p );
    vec2 f = fract( p );	
	vec2 u = f*f*(3.0-2.0*f);
    return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ), 
                     hash( i + vec2(1.0,0.0) ), u.x),
                mix( hash( i + vec2(0.0,1.0) ), 
                     hash( i + vec2(1.0,1.0) ), u.x), u.y);
}
// lighting
float diffuse(vec3 n,vec3 l,float p) {
    return pow(dot(n,l) * 0.4 + 0.6,p);
}
float specular(vec3 n,vec3 l,vec3 e,float s) {    
    float nrm = (s + 8.0) / (PI * 8.0);
    return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
}
// sky
vec3 getSkyColor(vec3 e) {
    e.y = (max(e.y,0.0)*0.8+0.2)*0.8;
    return vec3(pow(1.0-e.y,2.0), 1.0-e.y, 0.6+(1.0-e.y)*0.4) * 1.1;
}
// sea
float sea_octave(vec2 uv, float choppy) {
    uv += noise(uv);        
    vec2 wv = 1.0-abs(sin(uv));
    vec2 swv = abs(cos(uv));    
    wv = mix(wv,swv,wv);
    return pow(1.0-pow(wv.x * wv.y,0.65),choppy);
}
float map(vec3 p,float time) {
    float freq = SEA_FREQ;
    float amp = SEA_HEIGHT;
    float choppy = SEA_CHOPPY;
    vec2 uv = p.xz; uv.x *= 0.75;
    
    float d, h = 0.0;    
    for(int i = 0; i < ITER_GEOMETRY; i++) {        
    	d = sea_octave((uv+getSEA_TIME(time))*freq,choppy);
    	d += sea_octave((uv-getSEA_TIME(time))*freq,choppy);
        h += d * amp;        
    	uv *= getoctave_m(); freq *= 1.9; amp *= 0.22;
        choppy = mix(choppy,1.0,0.2);
    }
    return p.y - h;
}

float map_detailed(vec3 p,float time) {
    float freq = SEA_FREQ;
    float amp = SEA_HEIGHT;
    float choppy = SEA_CHOPPY;
    vec2 uv = p.xz; uv.x *= 0.75;
    
    float d, h = 0.0;    
    for(int i = 0; i < ITER_FRAGMENT; i++) {        
    	d = sea_octave((uv+getSEA_TIME(time))*freq,choppy);
    	d += sea_octave((uv-getSEA_TIME(time))*freq,choppy);
        h += d * amp;        
    	uv *= getoctave_m(); freq *= 1.9; amp *= 0.22;
        choppy = mix(choppy,1.0,0.2);
    }
    return p.y - h;
}
vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {  
    float fresnel = clamp(1.0 - dot(n,-eye), 0.0, 1.0);
    fresnel = pow(fresnel,3.0) * 0.5;
        
    vec3 reflected = getSkyColor(reflect(eye,n));    
    vec3 refracted = SEA_BASE + diffuse(n,l,80.0) * SEA_WATER_COLOR * 0.12; 
    
    vec3 color = mix(refracted,reflected,fresnel);
    
    float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0);
    color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
    
    color += vec3(specular(n,l,eye,60.0));
    
    return color;
}
// tracing
vec3 getNormal(vec3 p, float eps,float time) {
    vec3 n;
    n.y = map_detailed(p,time);    
    n.x = map_detailed(vec3(p.x+eps,p.y,p.z),time) - n.y;
    n.z = map_detailed(vec3(p.x,p.y,p.z+eps),time) - n.y;
    n.y = eps;
    return normalize(n);
}

float heightMapTracing(vec3 ori, vec3 dir, out vec3 p, float time) {  
    float tm = 0.0;
    float tx = 1000.0;    
    float hx = map(ori + dir * tx,time);
    if(hx > 0.0) {
        p = ori + dir * tx;
        return tx;   
    }
    float hm = map(ori + dir * tm,time);    
    float tmid = 0.0;
    for(int i = 0; i < NUM_STEPS; i++) {
        tmid = mix(tm,tx, hm/(hm-hx));                   
        p = ori + dir * tmid;                   
    	float hmid = map(p,time);
		if(hmid < 0.0) {
        	tx = tmid;
            hx = hmid;
        } else {
            tm = tmid;
            hm = hmid;
        }
    }
    return tmid;
}
vec3 getPixel(vec2 coord, float time, vec2 iResolution ) {    
    vec2 uv = coord / iResolution.xy;
    uv = uv * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;    
        
    // ray
    vec3 ang = vec3(sin(time*3.0)*0.1,sin(time)*0.2+0.3,time);    
    vec3 ori = vec3(0.0,3.5,time*5.0);
    vec3 dir = normalize(vec3(uv.xy,-2.0)); dir.z += length(uv) * 0.14;
    dir = normalize(dir) * fromEuler(ang);
    
    // tracing
    vec3 p;
    heightMapTracing(ori,dir,p,time);
    vec3 dist = p - ori;
    vec3 n = getNormal(p, dot(dist,dist) * getEPSILON_NRM(iResolution),time);
    vec3 light = normalize(vec3(0.0,1.0,0.8)); 
             
    // color
    return mix(
        getSkyColor(dir),
        getSeaColor(p,n,light,dir,dist),
        pow(smoothstep(0.0,-0.02,dir.y),0.2));
}

// main
void fragment() 
{
    float time = TIME * 0.02  + iMouse.x*0.04;
	vec2 iResolution = 1.0 / SCREEN_PIXEL_SIZE;
	vec3 color = vec3(0,0,0);
	if(AA == 1){
	    for(float i = -1.0; i <= 1.0; i++) {
	        for(float j = -1.0; j <= 1.0; j++) {
	            vec2 uv = FRAGCOORD.xy+vec2(i,j)/3.0;
	    	    color += getPixel(uv, time,iResolution);
	        }
	    }
            color /= 9.0;		
	}
	// Anti aliasing off
	if(AA == 0){
           color = getPixel(FRAGCOORD.xy,time,iResolution);
	}
    
    // post
    COLOR = vec4(pow(color,vec3(0.65)), 1.0);
}
Tags
#shadertoy, convert, godot, Seascape, shader
This shader is a port from an existing Shadertoy project. Shadertoy shaders are by default protected under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0) license unless anything else has been stated by the author. For more info, see our License terms.

Related shaders

Grid shader tutorial

WRIP EFFECT WITH GODOT SHADER

Image Warp Shader

Subscribe
Notify of
guest

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
pend00
2 years ago

Wow! Impressive!

Kolosso
Kolosso
2 years ago

Side note: This is just a fragment shader, no vertex. This isn’t applicable for most games

Ada
Ada
2 years ago

The original is CC-BY-NC-SA, a ported version should be under the same license (ShareAlike), not CC0